home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
SGI Developer Toolbox 6.1
/
SGI Developer Toolbox 6.1 - Disc 4.iso
/
public
/
bit
/
src
/
gui.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-08-01
|
101KB
|
4,302 lines
/*
* $Id: gui.c,v 0.91 1994/02/20 00:53:09 zhao Pre-Release $
*
*. This file is part of BIT shareware package. After the two weeks of
* free evaluation period, you are encouraged (required) to register
* your copy for a small registration fee, which is $35 for personal use
* and $50 for commercial, government and institutional use.
*
* Copyright(c) 1993, 1994 by T.C. Zhao.
* All rights reserved.
*
* Permission to use, copy, and distribute this software in its entirety
* for non-commercial purposes is hereby granted, provided that the
* above shareware and copyright notices and this permission notice
* appear in all copies and their documentation.
*
* This software may be modified for your own use, but modified versions
* may not be distributed without prior consent of the author.
*
* This software is provided "as is" without expressed or implied
* warranty of any kind.
*
*.
* This file contains
*
* A. Some simple utilites, like confirmation etc.
* B. Action buttons
* C. Help facilities.
* D Options
* E. XYPLOT
* F. Custom 4 xyplots
*/
#if !defined(lint) && defined(F_ID)
char *id_gui = "$Id: gui.c,v 0.91 1994/02/20 00:53:09 zhao Pre-Release $";
#endif
#include <stdio.h>
#include "utype.h"
#include "gui.h"
/********************************************************************
* Be nasty, always install my custom colors for FORMS, otherwise
* buttons might look bad
**********************************************************************/
struct maps_
{
int indx; /* index into forms colormap */
short r, g, b; /* primary color values */
};
/******************** Default colors **********************/
static struct maps_ fmc[] =
{
{FL_BLACK, 0, 0, 0},
{FL_RED, 255, 0, 0},
{FL_GREEN, 0, 255, 0},
{FL_YELLOW, 255, 255, 0},
{FL_BLUE, 0, 0, 255},
{FL_MAGENTA, 255, 0, 255},
{FL_CYAN, 0, 255, 255},
{FL_INACTIVE, 85, 85, 85},
{FL_WHITE, 255, 255, 255},
{FL_ORANGERED, 255, 71, 0},
{FL_INDIANRED, 198, 113, 113},
{FL_SLATEBLUE, 113, 113, 198},
{FL_GRAY68, 173, 173, 173},
{FL_GRAY76, 194, 194, 194},
{FL_GRAY91, 233, 233, 233},
{FL_GRAY92, 235, 235, 235},
{FL_GRAY12, 31, 31, 31},
{FL_DODGERBLUE, 63, 145, 255},
/*
* following colors are used internally by forms. Need to map these too
*/
{FL_MAGIC1, 163, 163, 163},
{FL_MAGIC2, 200, 200, 200}, /* brighter */
{FL_TOP_BOUND_COL, 204, 204, 204},
{FL_LEFT_BOUND_COL, 244, 244, 244},
{FL_BOT_BOUND_COL, 91, 91, 91},
{FL_RIGHT_BOUND_COL, 40, 40, 40}
};
/*******************************************************************
* Initialize forms, mostly to install default colormaps
*********************************************************************/
void
gui_init(void)
{
struct maps_ *p = fmc, *ps = p + sizeof(fmc) / sizeof(fmc[0]);
fl_init();
/*
* form_single is a bit varialbe to force single buffer to test how
* panels looks on Indigoes. Not documented.
*/
fl_doublebuf = !form_single && (getgdesc(GD_BITS_NORM_DBL_BLUE) >= 3);
while (p < ps)
{
fl_mapcolor(p->indx, p->r, p->g, p->b);
p++;
}
/* also initialize colors for messsage panels */
set_message_color(-1, -1, -1);
reset_time(); /* to get correct time_passed() reading */
}
/******************************************************************
* Some utilties based on FORMS library.
* yes_no, continue, getint etc.
******************************************************************/
#include <stdlib.h>
#include <string.h>
static void create_the_forms(void);
static const char *
break_long_lines(const char *s, int n)
{
static char buf[250];
char *p;
if (!s || n < 20 || strlen(s) < n)
return s;
Strncpy(buf, s, sizeof(buf) - 1);
if ((p = strchr(buf + n - 5, ' ')))
*p = '\n';
return buf;
}
static const char *
truncate_long_lines(const char *s, int n)
{
static char buf[250];
if (!s || strlen(s) < n)
return s;
strcpy(buf, s);
buf[n] = '\0';
return buf;
}
/****************************************************************
* Show a message and YES NO buttons
****************************************************************/
static FL_FORM *q_form;
static FL_OBJECT *q_str1, *q_str2, *q_str3, *q_yes, *q_no;
int
yes_no(const char *s1, const char *s2, const char *s3, int c)
{
int b = 0, place = c ? FL_PLACE_CENTER : FL_PLACE_HOTSPOT;
FL_OBJECT *ret;
short val;
create_the_forms();
fl_set_object_label(q_str1, s1);
/* don't want miss the messages when it is too long (clipped) */
fl_set_object_label(q_str2, truncate_long_lines(s2, 35));
fl_set_object_label(q_str3, break_long_lines(s3, 20));
fl_deactivate_all_forms();
bit_show_form(q_form, place, b, "Confirm");
while ((ret = fl_do_forms()) != q_no && ret != q_yes)
{
if (ret == FL_EVENT)
(void) bit_qread(&val);
}
fl_activate_all_forms();
bit_hide_form(q_form);
return (ret == q_yes);
}
/*****************************************************************
* Show a message and demand a mouse click
***************************************************************/
FL_FORM *cnt_form;
static FL_OBJECT *cnt_str1, *cnt_str2, *cnt_str3, *cnt_but;
void
TC_continue(const char *s1, const char *s2, const char *s3, int c)
{
FL_OBJECT *ret;
int b = 1, place = c ? FL_PLACE_CENTER : FL_PLACE_HOTSPOT;
short val;
create_the_forms();
fl_set_object_label(cnt_str1, s1);
fl_set_object_label(cnt_str2, s2);
fl_set_object_label(cnt_str3, s3);
fl_deactivate_all_forms();
bit_show_form(cnt_form, place, b, "Pause");
while ((ret = fl_do_forms()) != cnt_but)
{
if (ret == FL_EVENT)
(void) bit_qread(&val);
}
bit_hide_form(cnt_form);
fl_activate_all_forms();
}
/***************************************************************
* given a range, try to divided into nice steps for slider
***************************************************************/
static void
get_i_step(int r1, int r2, int *s1, int *s2)
{
*s2 = (r2 - r1 + 1) / 20;
if (*s2 > 100)
*s2 = (*s2 / 100) * 100;
else if (*s2 > 10)
*s2 = (*s2 / 10) * 10;
else if (*s2 > 4)
*s2 = 5;
else
*s2 = 2;
if ((*s1 = *s2 / 10) < 1)
*s1 = 1;
}
static FL_FORM *sinput;
static FL_OBJECT *ct, *prompt, *cancel, *inok, *reset;
/*****************************************************************
* if im is set, getint will return 0 whenever there is change.
* Cancel wil return -1, while ok return 1;
*****************************************************************/
int
getint(const char *p, int *in, int mini, int maxi, int im)
{
int def = (maxi + mini) / 2;
int large = (maxi - mini + 1) / 20, small = 1;
int done = 0, oin = *in; /* if im is set, oin has no meaning */
short val;
FL_OBJECT *ret;
create_the_forms();
get_i_step(mini, maxi, &small, &large);
fl_set_counter_bounds(ct, mini, maxi);
fl_set_counter_value(ct, *in);
fl_set_counter_step(ct, small, large);
fl_set_counter_precision(ct, 0);
fl_set_object_label(prompt, p ? p : "Integer");
fl_set_counter_return(ct, im);
deactivate_all_forms();
set_cursor(bit_show_form(sinput, FL_PLACE_MOUSE, 0, "Input"), CUR_HAND);
do
{
done = ((ret = fl_do_forms()) == cancel || ret == inok);
if (ret == FL_EVENT)
(void) bit_qread(&val);
else if (ret == reset)
fl_set_counter_value(ct, def);
}
while (!done && !im);
*in = (ret != cancel) ? fl_get_counter_value(ct) : oin;
if (done)
bit_hide_form(sinput);
fl_activate_all_forms();
return ret == cancel ? -1 : done;
}
/************************************************************
* Get a floating point number
************************************************************/
#include <math.h>
int
getfloat(const char *p, float *f, float minf,
float maxf, int im, int prec)
{
int def = (maxf + minf) / 2, done;
float small = 1.0 / pow(10.0, prec);
float large = small * 10;
short val;
FL_OBJECT *ret;
create_the_forms();
fl_set_counter_bounds(ct, minf, maxf);
fl_set_counter_value(ct, *f);
fl_set_counter_step(ct, small, large);
fl_set_counter_precision(ct, prec);
fl_set_object_label(prompt, p ? p : "Float");
deactivate_all_forms();
set_cursor(bit_show_form(sinput, FL_PLACE_MOUSE, 0, "Input"), CUR_HAND);
do
{
done = ((ret = fl_do_forms()) == cancel || ret == inok);
if (ret == FL_EVENT)
(void) bit_qread(&val);
else if (ret == reset)
fl_set_counter_value(ct, def);
}
while (!done && !im);
if (ret != cancel)
*f = fl_get_counter_value(ct);
if (done)
bit_hide_form(sinput);
fl_activate_all_forms();
return ret == cancel ? -1 : done;
}
/*************************************************************
* Get a string from keyboard
**********************************************************{**/
static FL_FORM *input_form;
typedef void (*VStrFptr) (const char *);
static VStrFptr strcb;
void
set_getstring_cb(VStrFptr f)
{
strcb = f;
}
/* ARGSUSED */
static void
str_ready(FL_OBJECT * ob, long q)
{
if (strcb)
strcb(fl_get_input(ob));
else
getstring_finish();
}
void
getstring_finish(void)
{
create_the_forms();
if (input_form->visible)
{
bit_hide_form(input_form);
fl_qenter(F1KEY, 10);
strcb = 0;
}
}
/* ARGSUSED */
static void
str_ok_cb(FL_OBJECT * ob, long q)
{
getstring_finish();
}
static FL_OBJECT *input_title;
static FL_OBJECT *input_val;
const char *
getstring(const char *title, const char *def, int block)
{
int b = always_border;
int place = block ? FL_PLACE_HOTSPOT : FL_PLACE_SIZE;
create_the_forms();
if (block)
deactivate_all_forms();
fl_set_object_label(input_title, title);
fl_set_input(input_val, def);
bit_show_form(input_form, place, b, "Input");
if (block)
{
int strfinish;
short val;
do
{
strfinish = (fl_do_forms() == FL_EVENT) &&
(bit_qread(&val) == F1KEY && val == 10);
}
while (!strfinish);
fl_activate_all_forms();
}
return (fl_get_input(input_val));
}
/***********************************************************
* END OF getstring and associates
********************************************************}*/
/**********************************************************/
static int llcol1 = FL_RED, llcol2 = FL_BLACK, llcol3 = FL_BLACK;
void
set_message_color(int col1, int col2, int col3)
{
create_the_forms();
if (col1 >= 0)
llcol1 = col1;
if (col2 >= 0)
llcol2 = col2;
if (col3 >= 0)
llcol3 = col3;
fl_set_object_lcol(cnt_str1, llcol1);
fl_set_object_lcol(cnt_str2, llcol2);
fl_set_object_lcol(cnt_str3, llcol3);
fl_set_object_lcol(q_str1, llcol1);
fl_set_object_lcol(q_str2, llcol2);
fl_set_object_lcol(q_str3, llcol3);
}
void
get_message_color(int *c1, int *c2, int *c3)
{
create_the_forms();
*c1 = llcol1;
*c2 = llcol2;
*c3 = llcol3;
}
/****************************************************************
* the form definations
****************************************************************/
static void
box_vert(float x, float y, float w, float h)
{
long xy[2];
xy[0] = x;
xy[1] = y + 0.5 * h;
v2i(xy);
xy[0] = x + 0.5 * w;
xy[1] = y;
v2i(xy);
xy[0] = x + w;
xy[1] = y + 0.5 * h;
v2i(xy);
xy[0] = x + 0.5 * w;
xy[1] = y + h;
v2i(xy);
}
/* ARGSUSED */
static int
draw_box(FL_OBJECT * ob, int ev, float x, float y, char k)
{
if (ev == FL_DRAW)
{
set_current_window(ob->form->window);
reshapeviewport();
bgnpolygon();
cpack(0xffff);
box_vert(ob->x, ob->y, ob->w, ob->h);
endpolygon();
linewidth(2);
bgnclosedline();
cpack(0);
box_vert(ob->x, ob->y, ob->w, ob->h);
endclosedline();
linewidth(1);
}
return 0;
}
/****************************************************************
* Add a bitmap of bang ! to the message panel
****************************************************************/
#include "bitmaps/warn.xbm"
#include "bitmaps/q.xbm"
static void
add_warn_icon(float x, float y, float w, float h)
{
FL_OBJECT *obj;
obj = fl_add_free(FL_SLEEPING_FREE, x, y, w, h, "", draw_box);
obj = fl_add_bitmap(FL_NORMAL_BITMAP, x, y, w, h, "");
fl_set_bitmap(obj, warn_width, warn_height, warn_bits);
fl_set_object_color(obj, 0, FL_YELLOW);
}
/*****************************************************************
* Add a bitmap of question mark ? to the confirm panel
*****************************************************************/
static void
add_q_icon(float x, float y, float w, float h)
{
FL_OBJECT *obj;
obj = fl_add_free(FL_SLEEPING_FREE, x, y, w, h, "", draw_box);
obj = fl_add_bitmap(FL_NORMAL_BITMAP, x, y, w, h, "");
fl_set_bitmap(obj, q_width, q_height, q_bits);
fl_set_object_color(obj, 0, FL_YELLOW);
}
static void
create_form_sinput(void)
{
FL_OBJECT *obj;
sinput = fl_bgn_form(FL_NO_BOX, 285.0, 105.0);
obj = fl_add_box(FL_UP_BOX, 0.0, 0.0, 285.0, 105.0, "");
fl_set_object_color(obj, 9, 47);
ct = obj = fl_add_counter(FL_NORMAL_COUNTER, 40.0, 40.0, 200.0, 30.0, "");
fl_set_object_color(obj, 12, 4);
fl_set_object_lcol(obj, 4);
fl_set_object_lsize(obj, FL_SMALL_FONT);
fl_set_object_lstyle(obj, FL_BOLD_STYLE);
prompt = obj = fl_add_text(FL_NT, 5.0, 75.0, 270.0, 20.0, "Text");
fl_set_object_lcol(obj, 4);
fl_set_object_align(obj, FL_ALIGN_CENTER);
fl_set_object_lstyle(obj, FL_BOLD_STYLE);
cancel = obj = fl_add_button(FL_NB, 100.0, 8.0, 85.0, 25.0, "Cancel");
fl_set_object_lsize(obj, 10.0);
fl_set_object_color(obj, 47, 1);
inok = obj = fl_add_button(FL_RETURN_BUTTON, 192.0, 8.0, 80.0, 25.0, "OK");
fl_set_object_lsize(obj, 10.0);
fl_set_object_color(obj, 47, 2);
reset = obj = fl_add_button(FL_NB, 10.0, 8.0, 85.0, 25.0, "Reset");
fl_set_object_lsize(obj, 10.0);
fl_set_object_color(obj, 47, 3);
fl_end_form();
}
static void
create_input_form(void)
{
FL_OBJECT *obj;
input_form = fl_bgn_form(FL_UP_BOX, 285.0, 100.0);
input_title = obj = fl_add_text(FL_NT, 15.0, 70.0, 260.0, 20.0, "");
fl_set_object_align(obj, FL_ALIGN_CENTER);
fl_set_object_lstyle(obj, 6);
input_val = obj = fl_add_input(FL_NI, 10.0, 40.0, 265.0, 20.0, "");
fl_set_object_boxtype(obj, FL_BORDER_BOX);
fl_set_object_color(obj, 47, 51);
fl_set_object_lsize(obj, 10.0);
fl_set_call_back(obj, str_ready, 0);
obj = fl_add_button(FL_NB, 105.0, 10.0, 60.0, 25.0, "OK");
fl_set_call_back(obj, str_ok_cb, 0);
fl_set_object_lsize(obj, 10.0);
fl_end_form();
fl_set_form_hotspot(input_form, 105 + 30, 10 + 12.5);
}
static void
create_yesno_form(void)
{
FL_OBJECT *obj;
q_form = fl_bgn_form(FL_UP_BOX, 300.0, 110.0);
q_str1 = obj = fl_add_box(FL_NO_BOX, 10.0, 80.0, 280.0, 20.0, "");
fl_set_object_lstyle(obj, FL_BOLD_STYLE);
q_str2 = obj = fl_add_box(FL_NO_BOX, 10.0, 62.0, 280.0, 15.0, "");
fl_set_object_lsize(obj, 10.0);
q_str3 = obj = fl_add_box(FL_NO_BOX, 10.0, 42.0, 280.0, 20.0, "");
fl_set_object_lsize(obj, 10.0);
q_no = obj = fl_add_button(FL_NB, 30.0, 10.0, 70.0, 25.0, "No");
fl_set_object_lsize(obj, 10.0);
fl_set_object_shortcut(obj, "n");
q_yes = obj = fl_add_button(FL_NB, 200.0, 10.0, 70.0, 25.0, "Yes");
fl_set_object_lsize(obj, 10.0);
fl_set_object_shortcut(obj, "y");
add_q_icon(10, 110.0 - 40, 30.0, 30.0);
fl_end_form();
fl_set_form_hotspot(q_form, 200 + 35, 10 + 12);
}
static void
create_cnt_form(void)
{
cnt_form = fl_bgn_form(FL_UP_BOX, 420.0, 130.0);
cnt_str1 = fl_add_box(FL_NO_BOX, 10.0, 100.0, 400.0, 20.0, "");
cnt_str2 = fl_add_box(FL_NO_BOX, 10.0, 75.0, 400.0, 20.0, "");
cnt_str3 = fl_add_box(FL_NO_BOX, 10.0, 50.0, 400.0, 20.0, "");
fl_set_object_lstyle(cnt_str1, FL_BOLD_STYLE);
fl_set_object_lstyle(cnt_str2, 6); /* Times-Roman */
fl_set_object_lstyle(cnt_str3, 6); /* Times-Roman */
fl_set_object_lsize(cnt_str1, 11.0);
fl_set_object_lsize(cnt_str2, 11.0);
fl_set_object_lsize(cnt_str3, 11.0);
cnt_but = fl_add_button(FL_RETB, 300.0, 10.0, 105.0, 30.0, "Continue");
cnt_form->doublebuf = 0;
add_warn_icon(10.0, 130.0 - 50.0, 34.0, 34.0);
fl_end_form();
fl_set_form_hotspot(cnt_form, 300 + 53, 30);
}
static void
create_the_forms(void)
{
static int formok;
if (!formok)
{
create_form_sinput();
create_yesno_form();
create_cnt_form();
create_input_form();
formok = 1;
}
}
/*****************************************************************
* Actions
****************************************************************{*/
#include <stdio.h>
#include <string.h>
#include "mac.h"
#include "dmalloc.h"
#define MAXMACT 3 /* maximum action tables */
#define MAXSACT 10 /* maximum actin shown perscreen */
#define MAXLBL 15 /* button label lenght */
/* structures for one action */
typedef struct s_act
{
struct s_act *next; /* link */
int ret; /* return value if bind is 0 */
VLfptr bind; /* bind funciton */
char label[MAXLBL + 1]; /* label */
}
S_ACT;
/* action structures */
typedef struct _action_t
{
int total; /* how many are defined */
char *title; /* title */
char *fhelp; /* help file name */
S_ACT *head, *tail; /* link */
}
M_ACT;
static M_ACT action[MAXMACT];
static void create_form_action(void);
static int do_h; /* index in do_action */
/*
* Call back routine if any button is pressed. fake_it doesn't
* really do anything, it just lends its prototype.
*/
/* ARGSUSED */
static void
fake_it(FL_OBJECT * NotUsed, long a)
{
register S_ACT *q;
for (q = action[do_h].head; q && q->ret != a; q = q->next)
;
if (q && q->bind)
q->bind(a);
}
/********** Help ****************************/
/* ARGSUSED */
static void
help_action(FL_OBJECT * ob, long q)
{
M_ACT *p;
p = &action[do_h];
print_help(p->fhelp, p->title, 0, 0, 0, 0);
}
static int action_warn = 1;
static int
bad_handle(int h)
{
if (h < 0 || h >= MAXMACT)
{
M_info("Action", "Bad handle %d", h);
if (action_warn)
Bark("ActionCheckHandle", "Bad handle");
return -1;
}
return 0;
}
/****************** Initialze table ************************/
static void
init_action(void)
{
static int init;
M_ACT *act = action + MAXMACT;
if (!init)
{
while (--act >= action)
{
act->title = act->fhelp = 0;
act->head = act->tail = 0;
act->total = 0;
}
init = 1;
}
}
static int
find_avail_index(void)
{
int i;
static int actwarned;
for (i = 0; i < MAXMACT; i++)
{
if (!action[i].title)
return i;
}
/* it is in bad taste to bitch more than once */
if (!actwarned)
{
Bark("Action", "ActIndex out of bounds");
actwarned = 1;
}
return -1;
}
static void *
create_new_node(size_t nbytes)
{
S_ACT *p = malloc(nbytes);
if (p)
{
p->next = 0;
p->label[0] = '\0';
}
return p;
}
/*****************************************************
* Global functions to get a new table index
****************************************************/
int
define_action(const char *title, const char *hfile)
{
int index;
M_ACT *p;
init_action();
create_form_action();
if ((index = find_avail_index()) < 0)
return -1;
p = &action[index];
p->title = strdup((title && *title) ? title : "Untitled");
/* add help file only requested */
if (hfile && *hfile)
p->fhelp = strdup(hfile);
p->head = p->tail = 0;
return index;
}
/***************************************************************
* Add one more entries to the action table
**************************************************************/
int
addto_action(int handle, const char *label, VLfptr bind)
{
M_ACT *p;
S_ACT *new;
if (!label || !*label || bad_handle(handle))
return -1;
if (!(new = create_new_node(sizeof(S_ACT))))
return -1;
p = &action[handle];
Strncpy(new->label, label, MAXLBL);
new->bind = bind;
new->ret = p->total;
if (!p->head)
p->head = new;
else
p->tail->next = new;
p->tail = new;
p->total++;
return new->ret;
}
/********* Free a singly-linked list **********/
static void
free_list(S_ACT * head)
{
register S_ACT *p, *q;
for (p = head; p; p = q)
{
q = p->next;
free(p);
}
}
void
free_action(int handle)
{
M_ACT *p;
if (!(handle < 0 || handle >= MAXMACT))
{
p = &action[handle];
Free(p->title);
Free(p->fhelp);
free_list(p->head);
p->head = p->tail = 0;
p->total = 0;
}
}
void
free_all_actions(void)
{
int i;
for (i = 0; i < MAXMACT; i++)
if (action[i].title)
free_action(i);
}
/***********************************************************
* actually doing it
***********************************************************/
static int maxact;
static FL_FORM *action_form;
static FL_OBJECT *bact[MAXSACT], *up, *down, *end, *ahelp;
/* show action buttons. A limited no. per screen */
static void
load_action(S_ACT * head, int offset)
{
register int i = 0;
register S_ACT *p = head;
for (i = 0, p = head; p && i < offset; i++, p = p->next)
;
if (!p)
return;
fl_freeze_form(action_form);
for (i = 0; i < maxact && p; i++, p = p->next)
{
fl_show_object(bact[i]);
fl_set_object_label(bact[i], p->label);
fl_set_call_back(bact[i], fake_it, p->ret);
}
for (; i < maxact; i++)
fl_hide_object_only(bact[i]);
fl_unfreeze_form(action_form);
return;
}
/******************************************************
* Global actiavation routine
*****************************************************/
int
do_action(int handle)
{
int bd = 1, i = 0, done;
static int lasthandle = -1, offset;
M_ACT *p;
FL_OBJECT *ret;
short val;
if (bad_handle(handle) || !action[handle].head)
return -1;
create_form_action();
p = &action[handle];
fl_set_object_label(ahelp, p->title ? p->title : "Action");
if (lasthandle != handle)
{
offset = 0;
if (p->total < maxact)
{
fl_hide_object(up);
fl_hide_object(down);
}
else
{
fl_show_object(up);
fl_show_object(down);
}
}
do_h = handle;
load_action(p->head, offset);
deactivate_all_forms();
bit_show_form(action_form, FL_PLACE_MOUSE, bd, "Action");
done = 0;
do
{
ret = fl_do_forms();
if (ret == up && offset >= maxact)
{
offset -= maxact;
load_action(p->head, offset);
}
else if (ret == down && offset + maxact <= p->total)
{
offset += maxact;
load_action(p->head, offset);
}
else if (ret == end)
{
done = 1;
}
else if (ret == FL_EVENT)
{
(void) bit_qread(&val);
}
else
{
for (i = 0; i < MAXMACT; i++)
if (bact[i] == ret)
return i + offset;
}
}
while (!done);
lasthandle = handle;
bit_hide_form(action_form);
fl_activate_all_forms();
return 0;
}
static void
create_form_action(void)
{
float x, y, dx, dy;
int i, j;
FL_OBJECT *obj;
static int fmade;
if (fmade)
return;
action_form = fl_bgn_form(FL_UP_BOX, 265.0, 295.0);
obj = fl_add_button(FL_HB, 0.0, 0.0, 265.0, 295.0, "");
fl_set_call_back(obj, help_action, 0);
up = fl_add_button(FL_NB, 20.0, 10.0, 30.0, 30.0, "@8");
fl_set_object_color(up, 47, 10);
fl_set_object_lcol(up, 4);
down = fl_add_button(FL_NB, 50.0, 10.0, 30.0, 30.0, "@2");
fl_set_object_color(down, 47, 10);
fl_set_object_lcol(down, 4);
ahelp = fl_add_button(FL_NB, 40.0, 248.0, 184.0, 32.0, "");
fl_set_object_boxtype(ahelp, FL_FRAME_BOX);
fl_set_object_lsize(ahelp, 16.0);
fl_set_object_lcol(ahelp, FL_BLUE);
fl_set_object_lstyle(ahelp, FL_ENGRAVED_STYLE);
fl_set_call_back(ahelp, help_action, 0);
end = fl_add_button(FL_NB, 130.0, 10.0, 110.0, 30.0, "Done");
maxact = 0;
dx = 120.0, dy = 35.0, x = 15;
for (j = 0, y = 200; j < MAXSACT && y > 40; j += 2, x = 15, y -= dy)
{
for (i = 0; i < 2; i++, x += dx)
{
obj = fl_add_button(FL_NB, x, y, 110.0, 30.0, "");
fl_set_object_color(obj, 47, 1);
bact[maxact++] = obj;
}
}
fl_end_form();
fmade = 1;
}
/***************************************************************
* END OF ACTION
*************************************************************}*/
/******************************************************************
* HELP facilities
* for all help files and initialization, configuration files, the
* program will seach System dir first.
***************************************************************{*/
#include <stdlib.h>
static void create_form_help(void);
static FL_FORM *helpfm;
static FL_OBJECT *helpdone, *hbrowser;
struct helps
{
int index;
const char *title; /* help title */
const char *fname; /* help filename */
};
/* the order is not important */
static struct helps hstruct[] =
{
{HELP_CNTL, "ControlPanel", "cntl.hlp"},
{HELP_COLEDIT, "Edit Color", "pixtran.hlp"},
{HELP_COLOR, "ColorSelect", "color.hlp"},
{HELP_CP, "Cut & Paste", "cp.hlp"},
{HELP_CROP, "Crop", "crop.hlp"},
{HELP_EDIT, "Editing", "edit.hlp"},
{HELP_FSELECT, "FileSelector", "fselect.hlp"},
{HELP_INFO, "InfoPanel", "info.hlp"},
{HELP_LOAD, "LoadFiles", "load.hlp"},
{HELP_LSCAN, "LinearScan", "lscan.hlp"},
{HELP_OPTION, "SetOption", "option.hlp"},
{HELP_ROTATE, "Rotate", "rotate.hlp"},
{HELP_SCALE, "Scale", "scale.hlp"},
{HELP_TEXT, "TextHelp", "text.hlp"},
{HELP_WRITE, "SaveToDisk", "write.hlp"},
{HELP_ZOOM, "Zoom", "zoom.hlp"},
{HELP_QUANT, "Quantization", "quant.hlp"},
{HELP_MARKING, "PlaceMarks", "marking.hlp"},
{HELP_ERASER, "Simple C&P", "scp.hlp"},
{HELP_PS, "PostScript Options", "ps.hlp"},
{HELP_PEDIT, "Pixel Edit", "pedit.hlp"},
{HELP_FILTER, "External Filters", "filter.hlp"},
{HELP_CONVOLV, "External Convolution Matrix", "convolv.hlp"},
{HELP_HIST, "Histogram Info", "hist.hlp"},
{HELP_JPEG, "JPEG parameters", "jpeg.hlp"},
{HELP_SMOOTH, "Smoothing", "smooth.hlp"},
{HELP_MERGE, "ImageMerge", "merge.hlp"},
{HELP_IBR, "ImageBrowser", "ibrowser.hlp"},
{HELP_MPEG, "MPEG Control", "mpeg.hlp"},
{HELP_PAINT, "PaintHelp", "paint.hlp"},
{HELP_IBBIND, "IbrowserBinding", "ibbind.hlp"}
};
/***********************************************************
* handle online help request
**********************************************************/
/* ARGSUSED */
void
help_cb(FL_OBJECT * nouse, long n)
{
struct helps *h = hstruct + sizeof(hstruct) / sizeof(hstruct[0]);
if (n >= 0)
{
/* search for the right file */
while (--h >= hstruct && n != h->index)
;
if (h < hstruct)
{ /* can't find it */
Bark("Help", "Bad HelpIndex");
return;
}
print_help(h->fname, h->title, 0, 0, 0, 0);
}
}
void
set_help_title(const char *ttt)
{
create_form_help();
fl_set_object_label(helpdone, ttt);
}
void
add_to_help(const char *line)
{
/* add_to_help may be called before help */
create_form_help();
fl_add_browser_line(hbrowser, line);
}
void
insert_help(const char *line, int n)
{
fl_insert_browser_line(hbrowser, n, line);
}
#include "extern.h"
/*** given a filename and load it into the browser ***/
void
load_help(const char *fname, const char *title)
{
FILE *fp;
char localstr[1024];
create_form_help();
set_help_title((title && *title) ? title : fname);
if ((fp = get_HELPfile_fp(fname, "r")) == 0)
{
fl_add_browser_line(hbrowser, " ");
sprintf(localstr, "@C1file %s not found", fname);
fl_add_browser_line(hbrowser, localstr);
}
else
{
fclose(fp);
strcpy(localstr, helppath);
strcat(localstr, fname);
fl_load_browser(hbrowser, localstr);
}
#ifndef X1Y1
{
char moreinfo[1024];
sprintf(moreinfo, infofmt, helppath);
/* bitch about sharewhere */
fl_add_browser_line(hbrowser, " ");
fl_add_browser_line(hbrowser, sharewh);
fl_add_browser_line(hbrowser, dontforget);
fl_add_browser_line(hbrowser, moreinfo);
fl_add_browser_line(hbrowser, " ");
insert_help(" ", 1);
insert_help(moreinfo, 1);
insert_help(dontforget, 1);
insert_help(sharewh, 1);
insert_help(" ", 1);
}
#endif
}
/* show a loaded browser */
void
show_help(int x, int y, int w, int h, int b)
{
int otherfb, rcol, place;
long rwin, cwin;
int border = b || (always_border && (b >= 0));
/* check if overlay is active */
if ((otherfb = rubber_on_screen(&rwin, &rcol)))
{
set_current_window(rwin);
rubber_hide();
}
create_form_help();
fl_deactivate_all_forms();
if (w < 0 && h < 0)
{ /* center */
place = FL_PLACE_CENTER;
}
else if (w > 200 && h > 200)
{
prefposition(x, x + w - 1, y, y + h - 1);
place = FL_PLACE_FREE;
}
else
{
place = FL_PLACE_MOUSE;
}
cwin = bit_show_form(helpfm, place, border, "Help");
/* now redraw overlay so that it lies under help form */
if (otherfb)
{
set_current_window(rwin);
rubber_show(rcol);
}
if (place != FL_PLACE_CENTER)
set_current_window(cwin);
}
void
clear_help(void)
{
fl_clear_browser(hbrowser);
}
/* ARGSUSED */
static void
finish_help(FL_OBJECT * ret, long what)
{
bit_hide_form(helpfm);
fl_clear_browser(hbrowser);
fl_activate_all_forms();
}
/**** this is the function that should be called ****/
void
print_help(const char *fname, const char *title, int x, int y, int w, int h)
{
load_help(fname, title);
show_help(x, y, w, h, always_border);
}
static void
create_form_help(void)
{
FL_OBJECT *obj;
if (helpfm)
return;
helpfm = fl_bgn_form(FL_NO_BOX, 535.0, 405.0);
obj = fl_add_box(FL_DOWN_BOX, 0.0, 0.0, 535.0, 405.0, "");
fl_set_object_color(obj, 9, 47);
hbrowser = obj = fl_add_browser(FL_NBR, 10.0, 10.0, 510.0, 350.0, "");
fl_set_object_boxtype(obj, FL_SHADOW_BOX);
fl_set_object_color(obj, 53, 3);
fl_set_browser_fontsize(obj, 11.0);
helpdone = obj = fl_add_button(FL_NB, 140.0, 365.0, 254.0, 28.0, "");
fl_set_object_boxtype(obj, FL_FRAME_BOX);
fl_set_object_color(obj, 47, 2);
fl_set_object_lcol(obj, 4);
fl_set_object_lstyle(obj, FL_BOLD_STYLE);
fl_set_object_lsize(obj, 16.0);
fl_set_call_back(obj, finish_help, 0);
fl_end_form();
fl_clear_browser(hbrowser);
}
/*******************************************************************
* END OF help related routines
***************************************************************}*/
/*************************************************************
* Options: multiple choices. simplar to popup except
* we have the variable names and some brief info about
* the meaning of the variables
*************************************************************/
#include "dmalloc.h"
#include "mac.h"
#define MAXMOPT 4 /* max groups */
#define MAXSOPT 30 /* max questions per group */
#define MAXCHOICE 20 /* max. no. of choices per option */
#define MAXCHL 17 /* max. lenght of a choice */
/*
* data structure for the option
*/
typedef struct
{
int val, *valptr; /* variables */
char *vname, *what[2], *choices; /* name, explanation, string */
VIIpfptr cb; /* call back routine */
}
S_OPT;
typedef struct
{
char *helpfile;
char *title;
int total, nosave;
OptFunc imact;
char *timact;
S_OPT opt[MAXSOPT + 1];
}
M_OPT;
static M_OPT options[MAXMOPT];
static M_OPT *act;
static S_OPT *copt;
static int total, offset;
#define MAXSN 14 /* max per screen */
static FL_FORM *opt_form;
static FL_OBJECT *optok, *ocancel, *more, *save, *load, *help;
static FL_OBJECT *imabutt;
static FL_OBJECT *choice[MAXSN], *optlabel[MAXSN], *opt[MAXSN];
static int built_in;
/* local functions */
static void opt_init(void);
static void fill_choices(int, int, int);
static int fill_choice(char *, int, int);
static void create_form_option(void);
static int load_save(FL_OBJECT *, int);
static int save_opt(int, const char *);
static int load_opt(int, const char *);
static void
opt_init(void)
{
static int o_init;
if (!o_init)
{
create_form_option();
o_init = 1;
}
}
/*ARGSUSED*/
static void
opt_act_cb(FL_OBJECT * q, long p)
{
(options[p].imact) (p);
}
/* ARGSUSED */
static void
opt_help_cb(FL_OBJECT * q, long p)
{
if (act->helpfile)
print_help(act->helpfile, "", 0, 0, 0, 0);
}
/* ARGSUSED */
static void
opt_explain(FL_OBJECT * ha, long k)
{
int n = k + offset;
int c1, c2, c3;
get_message_color(&c1, &c2, &c3);
set_message_color(FL_BLUE, 0, 0);
if (copt[n].what[0])
TC_continue(copt[n].vname, copt[n].what[0], copt[n].what[1], 0);
else
TC_continue(copt[n].vname, "It is self-explanatory", "", 0);
set_message_color(c1, c2, c3);
return;
}
static int
get_newopt(const char *s)
{
register int i;
M_OPT *q = options;
for (i = 0; i < MAXMOPT; i++, q++)
if (!q->title || strcmp(q->title, s) == 0)
return i;
return -1;
}
static int
opt_badindex(int w)
{
int i;
if ((i = (w < 0 || w >= MAXMOPT || !options[w].title)))
Bark("OptIndex", "Bad handle");
return i;
}
/*
* all titles are potentially file names, there should be no funny
* characters in the title
*/
int
def_option(const char *title, int nosave, const char *hpfile)
{
int handle;
M_OPT *q;
opt_init();
/* demand a title */
if (!title || !*title)
{
M_warn("Def_opt", "A title must be supplies");
return -1;
}
if ((handle = get_newopt(title)) < 0)
return -1;
q = options + handle;
q->helpfile = (hpfile && *hpfile) ? strdup(hpfile) : 0;
q->title = strdup(title);
q->total = 0;
q->nosave = nosave;
q->timact = 0;
return handle;
}
int
getopt_index(const char *title)
{
int i;
M_OPT *q = options;
if (!title)
return -1;
for (i = 0; i < MAXMOPT; i++, q++)
{
if (q->title && strncmp(title, q->title, strlen(q->title)) == 0)
return i;
}
Bark("OptIndex", "%s: No such option", title);
return -1;
}
int
addto_option(int ind, const char *lab, const char *expl1,
const char *expl2, int *v, const char *choices, VIIpfptr cb)
{
if (opt_badindex(ind) || !lab || !v || !choices)
{
Bark("AddtoOpt", "Bad function argument");
return -1;
}
if (options[ind].total > MAXSOPT)
{
Bark("AddToOption", "MaxPerIndex out of bound");
return -1;
}
act = &options[ind];
copt = act->opt;
total = act->total;
copt += total;
copt->vname = strdup(lab);
copt->valptr = v;
copt->val = *v;
copt->choices = strdup(choices);
copt->cb = cb;
copt->what[0] = (expl1 && *expl1) ? strdup(expl1) : 0;
copt->what[1] = expl2 ? strdup(expl2) : 0;
act->total++;
return total;
}
int
set_option_act(int n, const char *ti, OptFunc cb)
{
if (opt_badindex(n) || !ti || !*ti || !cb)
return -1;
options[n].imact = cb;
options[n].timact = strdup(ti);
return 0;
}
#ifndef Free
#define Free(p) do { if(p) free(p); (p) = 0;} while (ZERO)
#endif
void
free_option(int ind)
{
register S_OPT *s;
if (opt_badindex(ind))
return;
act = &options[ind];
copt = act->opt;
total = act->total;
for (s = copt + total; copt < s; copt++)
{
Free(copt->vname);
Free(copt->what[0]);
Free(copt->what[1]);
Free(copt->choices);
}
Free(act->timact);
Free(act->helpfile);
Free(act->title);
}
void
free_all_options(void)
{
int i;
M_OPT *q = options;
for (i = 0; i < MAXMOPT; i++, q++)
if (q->title)
{
free_option(i);
q->title = 0;
}
}
int
do_option(int which)
{
int i, bd = 1;
FL_OBJECT *ret;
short val;
if (opt_badindex(which))
return -1;
act = &options[which];
total = act->total;
copt = act->opt;
fl_set_object_label(help, act->title);
(total > built_in ? fl_show_object : fl_hide_object) (more);
if (act->nosave)
{
fl_hide_object(load);
fl_hide_object(save);
}
else
{
fl_show_object(load);
fl_show_object(save);
}
if (act->imact)
{
fl_show_object(imabutt);
fl_set_object_label(imabutt, act->timact);
fl_set_call_back(imabutt, opt_act_cb, which);
}
else
{
fl_hide_object(imabutt);
}
offset = 0;
/*
* update the values of the local copy as the true value might've changed
* by means unknow to then option routines
*/
for (i = 0; i < total; i++)
copt[i].val = *(copt[i].valptr);
fill_choices(offset, total, 1);
deactivate_all_forms();
bit_show_form(opt_form, FL_PLACE_MOUSE, bd, "Options");
while ((ret = fl_do_forms()) != ocancel && ret != optok)
{
if (ret == FL_EVENT)
(void) bit_qread(&val);
else
load_save(ret, which);
}
fl_activate_all_forms();
bit_hide_form(opt_form);
if (ret == optok)
{
for (i = 0; i < act->total; i++)
*(copt[i].valptr) = copt[i].val;
}
else
{
for (i = 0; i < act->total; i++)
copt[i].val = *(copt[i].valptr);
}
for (i = 0; i < built_in; i++)
fl_clear_choice(choice[i]);
return ret == optok;
}
/* take str1|str2 apart and return no. of enties */
static char bufarea[MAXCHOICE][MAXCHL];
static char *chbuf[MAXCHOICE];
/********************************************************************
* fill the choice with form "str1|str2...."
* NOTE: for every call by do_option, we need to update the local
* copies because the variable might've changed by ways unknown to
* the option routines
********************************************************************/
static int
fill_choice(char *choices, int l, int update)
{
int i, ii;
if (chbuf[0] == 0)
{
for (i = 0; i < MAXCHOICE; i++)
chbuf[i] = bufarea[i];
}
ii = sep_choices(choices, chbuf);
fl_clear_choice(choice[l]);
for (i = 0; i < ii; i++)
fl_addto_choice(choice[l], chbuf[i]);
if (update)
copt[l + offset].val = *(copt[l + offset].valptr);
if (copt[l + offset].val < 0 || copt[l + offset].val >= ii)
{
M_warn("FillChoice", "%s: BadVal %d", copt[l + offset].vname,
copt[l + offset].val);
*(copt[l + offset].valptr) = copt[l + offset].val =
(copt[l + offset].val < 0) ? 0 : ii - 1;
}
fl_set_choice(choice[l], copt[l + offset].val + 1);
return ii;
}
/*************************************************************
* Fill all choices
************************************************************/
static void
fill_choices(int off, int all, int update)
{
int k;
fl_freeze_form(opt_form);
for (k = 0; k < built_in && k + off < all; k++)
{
fill_choice(copt[k + off].choices, k, update);
fl_set_object_label(optlabel[k], copt[k + off].vname);
fl_show_object(choice[k]);
fl_show_object(optlabel[k]);
fl_show_object(opt[k]);
}
for (; k < built_in; k++)
{
fl_hide_object_only(choice[k]);
fl_hide_object_only(opt[k]);
fl_hide_object_only(optlabel[k]);
}
fl_unfreeze_form(opt_form);
}
#define OPT_MAGIC "****"
#define M_LENGTH 4
static int
save_opt(int which, const char *fn)
{
FILE *fp;
int all, i;
char *ch;
if (opt_badindex(which) || !fn)
return -1;
if (!(fp = msg_fopen(fn, "w")))
return -1;
act = &options[which];
all = act->total;
fprintf(fp, "%s%s\n", OPT_MAGIC, act->title);
if (chbuf[0] == 0)
{
for (i = 0; i < MAXCHOICE; i++)
chbuf[i] = bufarea[i];
}
for (i = 0; i < all; i++)
{
ch = act->opt[i].choices;
(void) sep_choices(ch, chbuf);
fprintf(fp, "%25s: %s\n", act->opt[i].vname, chbuf[act->opt[i].val]);
}
fclose(fp);
return 0;
}
static int
check_optsig(FILE * fp)
{
char line[120];
if (!fgets(line, 120, fp) || strncmp(line, OPT_MAGIC, M_LENGTH))
{
Bark("CheckOptSig", "Not an option file");
return -1;
}
return getopt_index(line + M_LENGTH);
}
/* scan the option for varaible name and its value */
#include <stdlib.h>
static int
search_choice(char *choices, char *cstr)
{
int i, ii;
if (chbuf[0] == 0)
{
for (i = 0; i < MAXCHOICE; i++)
chbuf[i] = bufarea[i];
}
ii = sep_choices(choices, chbuf);
for (i = 0; i < ii; i++)
if (strcasecmp(chbuf[i], cstr) == 0)
return i;
return -1;
}
static int
search_vname(int ind, const char *vname, char *val, int set)
{
int i, n;
char *q;
M_OPT *p;
if (opt_badindex(ind))
return -1;
p = &options[ind];
n = p->total;
for (i = 0; i < n && strcasecmp(vname, p->opt[i].vname); i++)
;
if (i >= n)
return -1;
/* now get the value */
if ((n = search_choice(p->opt[i].choices, val)) < 0)
{ /* did not find */
n = strtol(val, &q, 10); /* check if a number */
if (val == q) /* bad conversion */
n = 0;
}
p->opt[i].val = n;
if (set)
*(p->opt[i].valptr) = n;
return 0;
}
static int
load_opt_fp(FILE * fp, int set, int ind)
{
int nerr = 0, err;
char line[130], vname[100], val[30];
while (fgets(line, sizeof(line), fp))
{
if (line[0] == '#' || line[0] == '!') /* comment */
continue;
if (!(err = (sscanf(line, " %[^:]: %s ", vname, val) != 2)))
err = search_vname(ind, vname, val, set);
if (err)
nerr++;
if (nerr > 4)
{
Bark("LoadOpt", "%d errorrs encountered", nerr);
return -1;
}
}
return 0;
}
/*
* Load option.
*/
int
load_optfile(const char *fn, int set)
{
FILE *fp;
int status1 = -1, status2 = -1, ind = -1;
if (!fn)
return -1;
/* try system directory first */
if ((fp = get_HELPfile_fp(fn, "r")) && (ind = check_optsig(fp)) >= 0)
{
status1 = load_opt_fp(fp, set, ind);
M_info("LoadOpt", "SysDir %s", status1 < 0 ? "NotOk" : "OK");
fclose(fp);
}
/* user directories */
if ((fp = get_BITfile_fp(fn, "r")) && (ind = check_optsig(fp)) >= 0)
{
status2 = load_opt_fp(fp, set, ind);
M_info("LoadOpt", "UserDir %s", status2 < 0 ? "NotOk" : "OK");
fclose(fp);
}
return (status1 < 0 && status2 < 0) ? -1 : 0;
}
static int
load_opt(int ind, const char *fn)
{
int match;
if ((match = load_optfile(fn, 0)) < 0 || ind != match)
return -1;
act = &options[match];
total = act->total;
copt = act->opt;
fill_choices(offset, total, 0);
return 0;
}
static int
load_save(FL_OBJECT * but, int ind)
{
const char *ext = "*.opt";
char tmp[1024];
const char *fn;
const char *prom = (but == save) ? "Filename to Save" : "Filename to Load";
sprintf(tmp, "%s.opt", act->title);
fn = getfilename(prom, bitpath, ext, tmp, 1);
return (but == save ? save_opt : load_opt) (ind, fn);
}
/*
* call back routines
*/
static void
get_choice_cb(FL_OBJECT * c, long i)
{
copt[i + offset].val = fl_get_choice(c) - 1;
if (copt[i + offset].cb)
copt[i + offset].cb(i + offset, &(copt[i + offset].val));
}
/* ARGSUSED */
static void
opt_nextpage_cb(FL_OBJECT * c, long a)
{
if ((offset + built_in) < total)
offset += built_in;
else
offset = 0;
fill_choices(offset, total, 0);
}
static void
create_form_option(void)
{
FL_OBJECT *obj;
float x, y, dx, dy;
int i;
opt_form = fl_bgn_form(FL_NO_BOX, 300.0, 370.0);
obj = fl_add_box(FL_UP_BOX, 0.0, 0.0, 300.0, 370.0, "");
fl_set_object_color(obj, FL_DODGERBLUE, 47);
obj = fl_add_button(FL_HB, 0, 0, 300.0, 370.0, "");
fl_set_call_back(obj, opt_help_cb, HELP_OPTION);
help = fl_add_button(FL_NB, 60.0, 325.0, 180.0, 30, "");
fl_set_object_boxtype(help, FL_RSHADOW_BOX);
fl_set_object_color(help, FL_ORANGERED, 47);
fl_set_object_lcol(help, 4);
fl_set_object_lstyle(help, FL_BOLD_STYLE);
fl_set_object_lsize(obj, 14.0);
fl_set_call_back(help, opt_help_cb, HELP_OPTION);
x = 70;
y = 45.0;
dx = 80;
dy = 20;
more = fl_add_button(FL_NB, x, y, dx, dy, "More");
fl_set_object_boxtype(more, FL_FLAT_BOX);
fl_set_object_lcol(more, 4);
fl_set_object_color(more, 47, FL_YELLOW);
fl_set_object_lstyle(more, FL_ITALIC_STYLE);
fl_set_call_back(more, opt_nextpage_cb, 0);
dx += 10;
x += dx;
dy += 5;
imabutt = obj = fl_add_button(FL_NB, x, y, dx, dy, "");
fl_set_object_lsize(obj, 10.0);
fl_set_object_color(obj, FL_MAGIC1, FL_YELLOW);
dx = 165.0, dy = 20.0, x = 10, y = 295;
for (i = 0; i < MAXSN && y > 70; i++, y -= dy, x = 10)
{
optlabel[i] = fl_add_text(FL_NORMAL_TEXT, x, y, dx, dy, "");
fl_set_object_boxtype(optlabel[i], FL_FLAT_BOX);
fl_set_object_align(optlabel[i], FL_ALIGN_RIGHT);
fl_set_object_lsize(optlabel[i], 10.0);
fl_set_object_lstyle(optlabel[i], FL_BOLD_STYLE);
fl_set_object_color(optlabel[i], FL_DODGERBLUE, 22);
opt[i] = fl_add_button(FL_HIDDEN_BUTTON, x, y, dx, dy, "");
fl_set_call_back(opt[i], opt_explain, i);
x += dx + 5;
choice[i] = fl_add_choice(FL_NORMAL_CHOICE, x, y, 105.0, dy, "");
fl_set_object_boxtype(choice[i], FL_BORDER_BOX);
fl_set_choice_fontsize(choice[i], 10.0);
fl_set_object_color(choice[i], 50, 0);
fl_set_call_back(choice[i], get_choice_cb, i);
}
built_in = i;
/* control buttons */
dx = 70.0;
dy = 25.0;
x = 10.0;
load = obj = fl_add_button(FL_NB, x, 10.0, dx, dy, "Load");
fl_set_object_lsize(obj, 10.0);
fl_set_object_color(load, 47, FL_RED);
x += dx;
save = obj = fl_add_button(FL_NB, x, 10.0, dx, dy, "Save");
fl_set_object_lsize(obj, 10.0);
fl_set_object_color(save, 47, FL_RED);
x += dx;
ocancel = obj = fl_add_button(FL_NB, x, 10.0, dx, dy, "Cancel");
fl_set_object_color(ocancel, 47, FL_RED);
fl_set_object_lsize(obj, 10.0);
x += dx;
optok = obj = fl_add_button(FL_NB, x, 10.0, dx, dy, "OK");
fl_set_object_lsize(obj, 10.0);
fl_set_object_color(obj, 47, FL_GREEN);
fl_end_form();
fl_set_form_hotspot(opt_form, (x + dx / 2), (10 + dy / 2));
}
/*****************************************************************
* Forms class xyplot. It is important to NOT to use dmalloc.h
* when fully debuged. This is an ugly hack!
******************************************************************/
#include <stdio.h>
#include <string.h>
#include "gl/gl.h"
#include "gl/device.h"
#include "fmclient.h"
#include "gui.h"
#include "dmalloc.h"
#define MAXTEXT 3
#define MAXTEXTL 40
#define XEXPAND 1.02 /* expand Xmax for better tics */
#define XTEXPAND 0.5 /* expand Xmax in terms of tics */
#define YEXPAND 1.002 /* expand Ymax for better tics */
typedef struct
{
float *x, *y; /* the xy data */
int n; /* No. of data points */
float xmin, xmax; /* x-axis extrema */
float ymin, ymax; /* y-axis extrema */
float ax, bx; /* x-axis scale */
float ay, by; /* y-axis scale */
int xi, yi, xf, yf; /* the true plotting area */
short intpl; /* > 1 to interpolate */
short within;
short always;
short autoxbounds;
short autoybounds;
short xmajor, xminor; /* xscale info */
short ymajor, yminor; /* yscale info */
short p_size, c_size;
char title[MAXTEXTL]; /* plot title */
char xlabel[MAXTEXTL]; /* x-axis label */
char ylabel[MAXTEXTL]; /* y-axis label */
float lsize, lstyle; /* label size and style */
float csize; /* current size */
float xtic, ytic, ll; /* working */
short pcol, lcol; /* plot color and lable color */
short vert[MAXTEXT]; /* direction */
short tcol[MAXTEXT];
short tstyle[MAXTEXT];
float tsize[MAXTEXT];
float tx[MAXTEXT], ty[MAXTEXT];
char text[MAXTEXT][MAXTEXTL];
}
Plot_h;
typedef Plot_h SPEC;
enum
{
LS_SOLID,
LS_DASHED,
LS_DOTTED,
LS_LINEPOINT,
LS_EMPTY
};
#define P_SIZE 3 /* square */
#define C_SIZE 4 /* circle size */
static int p_size, c_size;
static fmfonthandle thefont[5];
static void do_xyplot_tics(Plot_h *);
static void
init_ls(void)
{
static int ok;
if (!ok)
{
deflinestyle(LS_DASHED, 0x00ff);
deflinestyle(LS_DOTTED, 0x0180);
deflinestyle(LS_LINEPOINT, 0xe187);
deflinestyle(LS_EMPTY, 0);
thefont[0] = fmfindfont(FL_FONT_NAME_0);
thefont[1] = fmfindfont(FL_FONT_NAME_1);
thefont[2] = fmfindfont(FL_FONT_NAME_2);
thefont[3] = fmfindfont(FL_FONT_NAME_3);
thefont[4] = fmfindfont(FL_FONT_NAME_4);
}
}
static void
Line(float xi, float yi, float xf, float yf)
{
float ic1[2], ic2[2];
ic1[0] = xi;
ic1[1] = yi;
ic2[0] = xf;
ic2[1] = yf;
bgnline();
v2f(ic1);
v2f(ic2);
endline();
}
static void
vv(float x, float y)
{
float ff[2];
ff[0] = x;
ff[1] = y;
v2f(ff);
}
static float gen_tic(float, float, int, int);
static void
get_min_max(float *a, int n, float *fmin, float *fmax)
{
register float fi, fm, *f = a, *fend;
fi = a[0];
fm = a[0];
for (fend = f + n; f < fend; f++)
{
if (fi > *f)
fi = *f;
if (fm < *f)
fm = *f;
}
*fmin = fi;
*fmax = fm;
}
static hchar, wchar;
static void
draw_vert_text(int align, float x, float y, char *text,
int col, float size, int style)
{
fmfonthandle t;
double pagematrix[3][2];
int w;
t = fmscalefont(thefont[style], size);
w = fmgetstrwidth(t, text);
fmsetfont(t);
fmgetpagematrix(pagematrix);
fmrotatepagematrix(90.0);
switch (align)
{
case FL_ALIGN_TOP:
x -= (0.5 * hchar);
y -= w;
break;
case FL_ALIGN_BOTTOM:
x -= (0.5 * hchar);
break;
case FL_ALIGN_LEFT:
y -= (0.5 * w);
x += hchar;
break;
case FL_ALIGN_RIGHT:
y -= (0.5 * w);
break;
case FL_ALIGN_CENTER:
default:
x += (0.5 * hchar);
y -= (0.5 * w);
break;
}
cmov2i(x, y);
fl_color(col);
fmprstr(text);
fmsetpagematrix(pagematrix);
}
static void
draw_xyplot_text(FL_OBJECT * ob, int clr)
{
int i, c;
float fx, fy;
Plot_h *p = (Plot_h *) ob->spec;
set_current_window(ob->form->window);
for (i = 0; i < MAXTEXT; i++)
{
if (!p->text[i][0])
continue;
fx = p->ax * p->tx[i] + p->bx;
fy = p->ay * p->ty[i] + p->by;
c = clr ? ob->col1 : p->tcol[i];
if (p->vert[i])
{
draw_vert_text(FL_ALIGN_CENTER, fx, fy, p->text[i], c,
p->tsize[i], p->tstyle[i]);
}
else
{
fl_drw_text_beside(FL_ALIGN_CENTER, fx, fy, 0, 0,
c, p->tsize[i], p->tstyle[i], p->text[i]);
}
}
}
/***************************************************************
* this routine does the XYplot, including arbitary text
* Purposely not using hardware clipping, scrmask, because we
* want clamp the max. It does not take care of lables etc
* which fl_redraw_object will take care.
*************************************************************/
static void
doit(int s, FL_OBJECT * ob)
{
Plot_h *p = (Plot_h *) ob->spec;
float fx, fy, fyy, fx1, fy1;
float *x = p->x, *y = p->y, ymin = p->ymin, vymax, vymin;
float ax = p->ax, ay = p->ay, bx = p->bx, by = p->by;
int n1 = 0, n = p->n;
int i;
long ostyle = getlstyle();
/* rid of out of range data */
while (n1 < n && (p->x[n1] < 0.9 * p->xmin))
n1++;
while (n > 1 && (p->x[n - 1] > 1.1 * p->xmax))
n--;
vymax = ay * (1.1 * p->ymax) + by;
vymin = ay * (0.9 * p->ymin) + by;
set_current_window(ob->form->window);
reshapeviewport();
fl_color(p->pcol);
switch (s)
{
case FL_LINE_XYPLOT:
setlinestyle(0);
break;
case FL_DASHED_XYPLOT:
setlinestyle(LS_DASHED);
break;
case FL_DOTTED_XYPLOT:
setlinestyle(LS_DOTTED);
break;
case FL_LINEPOINT_XYPLOT:
setlinestyle(LS_LINEPOINT);
break;
case FL_POINTS_XYPLOT:
bgnpoint();
for (i = n1; i < n; i++)
{
fx = ax * x[i] + bx;
fy = ay * y[i] + by;
Range(fy, vymin, vymax);
vv(fx - 1, fy);
vv(fx, fy);
vv(fx + 1, fy);
vv(fx, fy - 1);
vv(fx, fy + 1);
}
endpoint();
setlinestyle(LS_EMPTY);
break;
case FL_SQUARE_XYPLOT:
case FL_LINESQUARE_XYPLOT:
case FL_ACTIVE_XYPLOT:
setlinestyle(0);
if (p_size)
{
for (i = n1; i < n; i++)
{
fx = ax * x[i] + bx;
fy = ay * y[i] + by;
Range(fy, vymin, vymax);
rect(fx - p_size, fy - p_size, fx + p_size, fy + p_size);
}
}
setlinestyle(s == FL_SQUARE_XYPLOT ? LS_EMPTY : 0);
break;
case FL_CIRCLE_XYPLOT:
case FL_LINECIRCLE_XYPLOT:
setlinestyle(0);
for (i = n1; i < n; i++)
{
fx = ax * x[i] + bx;
fy = ay * y[i] + by;
Range(fy, vymin, vymax);
circ(fx, fy, c_size);
}
setlinestyle(s == FL_CIRCLE_XYPLOT ? LS_EMPTY : 0);
break;
case FL_IMPULSE_XYPLOT:
case FL_IMPULSELINE_XYPLOT:
setlinestyle(0);
fyy = ay * ymin + by;
for (i = n1; i < n; i++)
{
fx = ax * x[i] + bx;
fy = ay * y[i] + by;
Range(fy, vymin, vymax);
Line(fx, fyy, fx, fy);
}
setlinestyle(s == FL_IMPULSE_XYPLOT ? LS_EMPTY : 0);
break;
case FL_LINEFILL_XYPLOT:
setlinestyle(0);
fyy = ay * ymin + by;
for (i = n1; i < n - 1; i++)
{
fx = ax * x[i] + bx;
fy = ay * y[i] + by;
Range(fy, vymin, vymax);
fx1 = ax * x[i + 1] + bx;
fy1 = ay * y[i + 1] + by;
Range(fy1, vymin, vymax);
bgnpolygon();
vv(fx, fyy);
vv(fx, fy);
vv(fx1, fy1);
vv(fx1, fyy);
endpolygon();
}
setlinestyle(LS_EMPTY);
break;
default:
setlinestyle(0);
break;
}
/* the bounding rectangle */
s = getlstyle();
setlinestyle(0);
fl_color(p->lcol);
recti(p->xi, p->yi, p->xf, p->yf);
/* the final drawing */
if (s != LS_EMPTY)
{
setlinestyle(s);
fl_color(p->pcol);
bgnline();
for (i = n1; i < n; i++)
{
fx = ax * x[i] + bx;
fy = ay * y[i] + by;
Range(fy, vymin, vymax);
vv(fx, fy);
}
endline();
}
/* additional text */
draw_xyplot_text(ob, 0);
setlinestyle(ostyle); /* restore the old style */
}
static void
nice_label(float tic, int minor, float f, char label[])
{
float crit = tic * minor;
if (tic > 1.0 && crit < 1000.0)
sprintf(label, "%.0f", f);
else if (crit >= 0.48 && crit <= 999.0)
sprintf(label, "%.1f", f);
else if (crit < 0.48 && crit >= 0.01)
sprintf(label, "%.2f", f);
else if (crit >= 1000.0)
sprintf(label, "%.0g", f);
else
sprintf(label, "%g", f);
}
static void
print_xtics(Plot_h * p)
{
register float xw, xr, xmin = p->xmin, xmax = p->xmax;
register int minor = p->xminor;
register float ax = p->ax, bx = p->bx;
float tic = p->xtic, ll = p->ll;
int yi = p->yi;
char label[120];
xmin = ((int) (xmin / tic)) * tic;
xmax *= XEXPAND;
xmax += XTEXPAND * tic;
xw = xmin;
fl_color(p->lcol);
while (xw <= xmax)
{
xr = ax * xw + bx;
Line(xr, yi - ll, xr, yi - 1);
nice_label(tic, minor, xw, label);
fl_drw_text(FL_ALIGN_TOP, xr, yi - ll + 2, 0.0, 0,
p->lcol, p->csize, p->lstyle, label);
xw += tic * minor;
}
/* minor tics */
xw = xmin;
while (xw <= xmax)
{
xr = ax * xw + bx;
Line(xr, yi, xr, yi - ll / 2);
xw += tic;
}
}
static void
print_ytics(Plot_h * p)
{
register float yw, yr, ymin = p->ymin, ymax = p->ymax;
register float ay = p->ay, by = p->by;
register int minor = p->yminor;
float tic = p->ytic, ll = p->ll;
int xi = p->xi;
char label[120];
fl_color(p->lcol);
ymax *= YEXPAND;
yw = ymin;
while (yw <= ymax)
{
yr = ay * yw + by;
Line(xi - ll, yr, xi, yr);
nice_label(tic, minor, yw, label);
fl_drw_text(FL_ALIGN_RIGHT, xi - ll + 2, yr,
0.0, 0.0, p->lcol, p->csize, p->lstyle, label);
yw += tic * minor;
}
/* minor tics */
fl_color(p->lcol);
yw = ymin;
while (yw <= ymax)
{
yr = ay * yw + by;
Line(xi - ll / 2, yr, xi, yr);
yw += tic;
}
}
#define LL 8
static void
get_char_size(int *w, int *h, float size, int style)
{
*h = fl_get_char_height(size, style);
*w = fl_get_string_width(size, style, "W");
}
static void
get_xyplot_bounds(SPEC * p)
{
/* get min and max */
if (p->autoxbounds)
get_min_max(p->x, p->n, &(p->xmin), &(p->xmax));
if (p->autoybounds)
get_min_max(p->y, p->n, &(p->ymin), &(p->ymax));
/* take care of horizonal line */
if ((p->ymax - p->ymin) <= 1.e-6)
{
p->ymin -= 1.0;
p->ymax += 1.0;
}
}
static void
draw_xyplot(FL_OBJECT * ob)
{
Plot_h *sp = (Plot_h *) ob->spec;
float xmin, xmax;
float ymin, ymax;
float xoff1, xoff2, yoff1, yoff2;
float xi, yi, xf, yf, xtic, ytic;
int ll;
int cc;
char tmp[12];
if (sp->n <= 0 || !sp->x || !sp->y)
return;
init_ls();
get_xyplot_bounds(sp);
xmin = sp->xmin;
xmax = sp->xmax;
ymin = sp->ymin;
ymax = sp->ymax;
fl_drw_box(ob->boxtype, ob->x, ob->y, ob->w, ob->h, ob->col1, FL_CHART_BW);
fl_drw_text_beside(ob->align, ob->x, ob->y, ob->w, ob->h,
ob->lcol, ob->lsize, ob->lstyle, ob->label);
/* sort of auto-adjust */
if (ob->h > 500 || ob->w > 500)
ll = (LL + ob->w / 500);
else if (ob->w <= 100 || ob->h <= 100)
ll = LL - 2;
else
ll = LL;
sp->ll = ll;
sp->csize = sp->lsize;
if ((ob->h <= 80. || ob->w <= 80.) && sp->lsize >= FL_SMALL_FONT)
{
sp->csize = FL_SMALL_FONT - 2;
}
else if ((ob->h >= 250 || ob->w >= 250) && (sp->lsize <= FL_SMALL_FONT))
{
sp->csize = FL_SMALL_FONT + 2;
}
p_size = sp->p_size;
c_size = sp->c_size;
if (ob->h > 400 && ob->w > 400 && sp->p_size && sp->c_size)
{
p_size++;
c_size++;
}
xmax *= XEXPAND;
ymax *= YEXPAND;
sp->xtic = xtic = (sp->xmajor <= 0 || sp->xminor < 0) ? -1.0 :
gen_tic(xmin, xmax, sp->xmajor, sp->xminor);
sp->ytic = ytic = (sp->ymajor <= 0 || sp->yminor < 0) ? -1.0 :
gen_tic(ymin, ymax, sp->ymajor, sp->yminor);
get_char_size(&wchar, &hchar, sp->csize, sp->lstyle);
/**** calculate space for title, tic marks etc ****/
cc = C_SIZE / 2;
yoff1 = yoff2 = xoff1 = xoff2 = sp->p_size + 2;
/* get xoff1 */
if (ytic > 0.0)
{
nice_label(ytic, sp->yminor, sp->ymax, tmp);
xoff1 += (fl_get_string_width(sp->csize, sp->lstyle, tmp) + ll);
}
xoff1 += (sp->ylabel[0] ? hchar : 1) + cc;
/* get xoff2. */
if (xtic > 0.0)
{
nice_label(ytic, sp->yminor, sp->xmax, tmp);
xoff2 += (0.6 * fl_get_string_width(sp->csize, sp->lstyle, tmp));
xmax += XTEXPAND * xtic;
}
/* yoff1 */
yoff1 += (xtic > 0.0) ? (ll + hchar + 1) : 0;
yoff1 += (sp->xlabel[0] ? hchar : 1) + cc;
/* yoff2 */
yoff2 += (sp->title[0] ? (1.5 * hchar) : 1) + cc;
sp->xi = xi = (ob->x + xoff1);
sp->yi = yi = (ob->y + yoff1);
sp->xf = xf = (ob->x + ob->w - xoff2);
sp->yf = yf = (ob->y + ob->h - yoff2);
sp->ax = (xf - xi) / (xmax - xmin);
sp->bx = xi - sp->ax * xmin;
sp->ay = (yf - yi) / (ymax - ymin);
sp->by = yi - sp->ay * ymin;
doit(ob->type, ob);
/* generate tic marks only if requested */
do_xyplot_tics(sp);
draw_vert_text(FL_ALIGN_LEFT, ob->x + 1, (yi + yf) * 0.5, sp->ylabel,
sp->lcol, sp->csize, sp->lstyle);
fl_drw_text(FL_ALIGN_BOTTOM, (xi + xf) * 0.5, ob->y + 2, 0.0, 0.0,
sp->lcol, sp->csize, sp->lstyle, sp->xlabel);
fl_drw_text(FL_ALIGN_BOTTOM, (xi + xf) * 0.5, yf + 2, 0.0, 0.0,
sp->lcol, sp->csize, sp->lstyle, sp->title);
}
/* ARGSUSED */
static void
free_xyplot(Plot_h * p)
{
if (!p)
return;
if (p->x)
free(p->x);
if (p->y)
free(p->y);
free(p);
p->x = p->y = 0;
}
#ifndef Abs
#define Abs(a) ((a)>0 ? (a):-(a))
#endif
/******* handle active_ xyplot mouse position change ********/
static void
redraw_point(Plot_h * p, int i, int clr)
{
float vymax = p->ay * (1.1 * p->ymax) + p->by;
float vymin = p->ay * (0.9 * p->ymin) + p->by;
float fx, fy, ofx, ofy;
ofx = fx = p->ax * p->x[i] + p->bx;
ofy = fy = p->ay * p->y[i] + p->by;
Range(fy, vymin, vymax);
if (p_size)
rect(fx - p_size, fy - p_size, fx + p_size, fy + p_size);
/* draw the nearest neighbors only if not clearing */
if (!clr)
{
if (i > 0 && p_size)
{
fx = p->ax * p->x[i - 1] + p->bx;
fy = p->ay * p->y[i - 1] + p->by;
rect(fx - p_size, fy - p_size, fx + p_size, fy + p_size);
}
if (i < p->n - 1 && p_size)
{
fx = p->ax * p->x[i + 1] + p->bx;
fy = p->ay * p->y[i + 1] + p->by;
rect(fx - p_size, fy - p_size, fx + p_size, fy + p_size);
}
}
/* and connecting lines */
bgnline();
if (i > 1 && !clr) /* next neibgor */
{
fx = p->ax * p->x[i - 2] + p->bx;
fy = p->ay * p->y[i - 2] + p->by;
vv(fx, fy);
}
if (i > 0)
{
fx = p->ax * p->x[i - 1] + p->bx;
fy = p->ay * p->y[i - 1] + p->by;
vv(fx, fy);
}
vv(ofx, ofy);
if (i < p->n - 1)
{
fx = p->ax * p->x[i + 1] + p->bx;
fy = p->ay * p->y[i + 1] + p->by;
vv(fx, fy);
}
if (i < (p->n - 2) && !clr)
{
fx = p->ax * p->x[i + 2] + p->bx;
fy = p->ay * p->y[i + 2] + p->by;
vv(fx, fy);
}
endline();
}
static void
do_xyplot_tics(Plot_h * p)
{
if (p->xtic > 0.0)
print_xtics(p);
if (p->ytic > 0.0)
print_ytics(p);
}
static void
draw_changed_part(FL_OBJECT * ob, int i, float x, float y)
{
Plot_h *sp = (Plot_h *) ob->spec;
if (ob->form->doublebuf)
{
sp->x[i] = x;
sp->y[i] = y;
fl_redraw_object(ob);
}
else
{
set_current_window(ob->form->window);
/* clear old drawing */
fl_color(ob->col1);
redraw_point(sp, i, 1);
/* make the bounding */
fl_color(sp->lcol);
recti(sp->xi, sp->yi, sp->xf, sp->yf);
/* draw the new point */
sp->x[i] = x;
sp->y[i] = y;
fl_color(sp->pcol);
redraw_point(sp, i, 0);
do_xyplot_tics(sp);
}
}
static int
handle_mouse(FL_OBJECT * ob, float mx, float my)
{
SPEC *sp = (SPEC *) ob->spec;
int i, found = 0;
float x, y, deltax, deltay, dx, dy;
static float lmx, lmy;
if (lmx == mx && lmy == my)
{
if (sp->within)
set_cursor(ob->form->window, CUR_S_CROSS);
return 0;
}
lmx = mx;
lmy = my;
deltax = (float) (p_size ? p_size : P_SIZE) / (sp->ax);
deltay = (float) (p_size ? p_size : P_SIZE) / (sp->ay);
deltax = Abs(deltax);
deltay = Abs(deltax);
x = (mx - sp->bx) / (sp->ax);
y = (my - sp->by) / (sp->ay);
if (sp->within <= 0)
{
/* see which points it is on, binary search ? */
for (i = 0; i < sp->n && !found; i++)
{
dx = x - sp->x[i];
dy = y - sp->y[i];
found = ((Abs(dx) <= deltax) && (Abs(dy) <= deltay));
}
if ((sp->within = (found ? i : 0)))
set_cursor(ob->form->window, CUR_S_CROSS);
return 0;
}
i = sp->within - 1;
if (y > sp->ymax)
y = sp->ymax;
else if (y < sp->ymin)
y = sp->ymin;
if (x < sp->xmin)
x = sp->xmin;
else if (x > sp->xmax)
x = sp->xmax;
/* first and last points must not allow to change */
if (i == 0 || i == sp->n - 1)
{
x = sp->x[i];
}
else
{
if (x >= sp->x[i + 1])
x = (0.99 * sp->x[i + 1]);
else if (x <= sp->x[i - 1])
x = (1.01 * sp->x[i - 1]);
}
draw_changed_part(ob, i, x, y);
sp->x[i] = x;
sp->y[i] = y;
return sp->always;
}
/* ARGSUSED */
static int
handle_it(FL_OBJECT * ob, int event, float mx, float my, char k)
{
int ret = 0;
switch (event)
{
case FL_DRAW:
draw_xyplot(ob);
break;
case FL_PUSH:
case FL_MOUSE:
ret = handle_mouse(ob, mx, my);
break;
case FL_RELEASE:
if (((SPEC *) ob->spec)->within > 0)
((SPEC *) ob->spec)->within *= -1;
ret = !((SPEC *) ob->spec)->always;
set_cursor(ob->form->window, CUR_DEFAULT);
break;
case FL_FREEMEM:
free_xyplot((Plot_h *) ob->spec);
break;
}
return ret;
}
FL_OBJECT *
fl_create_xyplot(int t, float x, float y, float w, float h,
const char *lab)
{
FL_OBJECT *ob;
Plot_h *sp;
int i;
ob = fl_make_object(FL_XYPLOT, t, x, y, w, h, lab, handle_it);
ob->boxtype = FL_CHART_BOXTYPE;
ob->col1 = FL_CHART_COL1;
ob->col2 = FL_CHART_COL1;
ob->align = FL_CHART_ALIGN;
ob->lcol = FL_CHART_LCOL;
ob->active = (t == FL_ACTIVE_XYPLOT);
ob->spec = calloc(1, sizeof(Plot_h));
/* initialization specific to xyplot stuff */
sp = (Plot_h *) ob->spec;
sp->x = malloc(1);
sp->y = malloc(1);
sp->n = -1;
sp->always = 0;
sp->xmajor = 5;
sp->xminor = 5;
sp->ymajor = 1;
sp->yminor = 2;
sp->pcol = sp->lcol = BLACK;/* plot colors */
sp->autoybounds = 1;
sp->autoxbounds = 1;
sp->lsize = FL_SMALL_FONT;
sp->lstyle = FL_NORMAL_STYLE;
sp->xmin = sp->ymin = 0.0;
sp->xmax = sp->ymax = 1.0;
sp->within = 0;
sp->p_size = P_SIZE;
sp->c_size = C_SIZE;
sp->intpl = 0;
for (i = 0; i < MAXTEXT; i++)
{
sp->vert[i] = 0; /* vertical */
sp->tcol[i] = sp->lcol;
sp->tsize[i] = FL_SMALL_FONT;
sp->text[i][0] = '\0';
}
return ob;
}
FL_OBJECT *
fl_add_xyplot(int type, float x, float y, float w, float h,
const char *lab)
{
FL_OBJECT *ob = fl_create_xyplot(type, x, y, w, h, lab);
fl_add_object(fl_current_form, ob);
return ob;
}
void
fl_clear_xyplot_text(FL_OBJECT * ob)
{
Plot_h *p;
int n;
if (ob == 0 || ob->objclass != FL_XYPLOT)
return;
/* need to do this only if in single buffer mode */
if (!ob->form->doublebuf && ob->form->visible && ob->visible)
draw_xyplot_text(ob, 1);
p = (SPEC *) ob->spec;
for (n = 0; n < MAXTEXT; n++)
p->text[n][0] = '\0';
}
/* specific routines */
void
fl_clear_xyplot(FL_OBJECT * ob)
{
Plot_h *p;
if (ob == 0 || ob->objclass != FL_XYPLOT)
return;
p = (Plot_h *) ob->spec;
if (p->x)
p->x = realloc(p->x, 4);
if (p->y)
p->y = realloc(p->y, 4);
p->n = -1;
fl_clear_xyplot_text(ob);
}
void
fl_set_xyplot_interpolate(FL_OBJECT * ob, int deg)
{
Plot_h *p;
if (ob == 0 || ob->objclass != FL_XYPLOT)
return;
p = (Plot_h *) ob->spec;
p->intpl = deg;
fl_redraw_object(ob);
}
/* Fill the xyplot stucture */
static void
fill_xyplot(FL_OBJECT * ob, float *x, float *y, int n,
const char *title, const char *xlab, const char *ylab)
{
Plot_h *p;
size_t mem;
if (ob == 0 || ob->objclass != FL_XYPLOT)
return;
if (n <= 0 || !x || !y)
return;
p = (Plot_h *) ob->spec;
mem = sizeof(float) * n;
if (!(p->x = p->x ? realloc(p->x, mem) : malloc(mem)) ||
!(p->y = p->y ? realloc(p->y, mem) : malloc(mem)))
{
return;
}
if (!(memcpy(p->x, x, sizeof(float) * n)) ||
! (memcpy(p->y, y, sizeof(float) * n)))
{
return;
}
p->n = n;
strncpy(p->title, title ? title : "", MAXTEXTL);
strncpy(p->xlabel, xlab ? xlab : "", MAXTEXTL);
strncpy(p->ylabel, ylab ? ylab : "", MAXTEXTL);
p->title[MAXTEXTL - 1] = '\0';
p->xlabel[MAXTEXTL - 1] = '\0';
p->ylabel[MAXTEXTL - 1] = '\0';
}
/* A hack to change a point for ACTIVE_XYPLOT *****/
void
fl_set_xyplot_point(FL_OBJECT * ob, float x, float y, int i)
{
Plot_h *p;
if (!ob || ob->objclass != FL_XYPLOT || !(p = (Plot_h *) ob->spec))
return;
if (ob->visible)
{
draw_changed_part(ob, i, x, y);
}
else
{
fl_redraw_object(ob);
}
if (i >= 0 && i < p->n)
{
p->x[i] = x;
p->y[i] = y;
}
}
/*******************************************************************
* This routine draws the XYPLOT only, NOT labels, titles etc.
******************************************************************/
void
fl_set_xyplot_only(FL_OBJECT * ob, float *x, float *y, int n,
const char *title, const char *xlab, const char *ylab)
{
int m;
Plot_h *p;
if (ob == 0 || ob->objclass != FL_XYPLOT)
return;
if (n <= 0 || !x || !y)
return;
fill_xyplot(ob, x, y, n, title, xlab, ylab);
p = (Plot_h *) ob->spec;
if (ob->form->doublebuf)
{
fl_redraw_object(ob);
}
else if (ob->form->window > 0)
{
/* for less flickering if continously changing */
m = C_SIZE / 2 + 1;
set_current_window(ob->form->window);
fl_color(ob->col1);
rectf(p->xi - m, p->yi - m, p->xf + m, p->yf + m);
doit(ob->type, ob);
do_xyplot_tics(p);
}
}
/***************************************************************
* This routine does it all
*************************************************************/
void
fl_set_xyplot(FL_OBJECT * ob, float *x, float *y, int n,
const char *title, const char *xlab, const char *ylab)
{
if (ob == 0 || ob->objclass != FL_XYPLOT)
return;
if (n <= 0 || !x || !y)
return;
fill_xyplot(ob, x, y, n, title, xlab, ylab);
fl_redraw_object(ob);
}
/* Specifying a negative value will leave the old setting alone */
void
fl_set_xyplot_autobounds(FL_OBJECT * ob, int xb, int yb)
{
Plot_h *p;
if (ob == 0 || ob->objclass != FL_XYPLOT)
return;
p = (Plot_h *) ob->spec;
if (xb >= 0)
p->autoxbounds = xb;
if (yb >= 0)
p->autoybounds = yb;
get_xyplot_bounds(p);
}
void
fl_get_xyplot(FL_OBJECT * ob, float *x, float *y, int *n)
{
Plot_h *p;
if (ob == 0 || ob->objclass != FL_XYPLOT || !x || !y)
return;
p = (Plot_h *) ob->spec;
if (p->n <= 0)
return;
*n = p->n;
if (memcpy(x, p->x, sizeof(float) * p->n) == 0 ||
memcpy(y, p->y, sizeof(float) * p->n) == 0)
{
return;
}
}
void
fl_set_xyplot_return(FL_OBJECT * ob, int y)
{
Plot_h *p;
if (ob == 0 || ob->objclass != FL_XYPLOT)
return;
if (!ob->active)
return;
p = (Plot_h *) ob->spec;
p->always = y;
}
void
fl_get_active_xyplot(FL_OBJECT * ob, float *x, float *y, int *i)
{
Plot_h *p;
int l;
if (ob == 0 || ob->objclass != FL_XYPLOT)
return;
p = (Plot_h *) ob->spec;
if (!p->within)
return;
l = *i = Abs(p->within) - 1;
*x = p->x[l];
*y = p->y[l];
}
void
fl_set_xyplot_xbounds(FL_OBJECT * ob, float xmin, float xmax)
{
Plot_h *p;
if (ob == 0 || ob->objclass != FL_XYPLOT || xmin >= xmax)
return;
p = (Plot_h *) ob->spec;
p->xmin = xmin;
p->xmax = xmax;
p->autoxbounds = 0;
fl_redraw_object(ob);
}
void
fl_set_xyplot_ybounds(FL_OBJECT * ob, float ymin, float ymax)
{
Plot_h *p;
if (ob == 0 || ob->objclass != FL_XYPLOT || ymin >= ymax)
return;
p = (Plot_h *) ob->spec;
p->ymin = ymin;
p->ymax = ymax;
p->autoybounds = 0;
fl_redraw_object(ob);
}
void
fl_set_xyplot_lsize(FL_OBJECT * ob, float size)
{
Plot_h *p;
if (ob == 0 || ob->objclass != FL_XYPLOT || size < 0.0 || size > 80.0)
return;
p = (Plot_h *) ob->spec;
p->lsize = size;
fl_redraw_object(ob);
}
void
fl_set_xyplot_legend(FL_OBJECT * ob, int size)
{
Plot_h *p;
if (ob == 0 || ob->objclass != FL_XYPLOT)
return;
p = (Plot_h *) ob->spec;
p->p_size = p->c_size = size;
}
void
fl_set_xyplot_colors(FL_OBJECT * ob, int pc, int lc)
{
Plot_h *p;
if (ob == 0 || ob->objclass != FL_XYPLOT)
return;
p = (Plot_h *) ob->spec;
if (pc >= 0)
p->pcol = pc;
if (lc >= 0)
p->lcol = lc;
fl_redraw_object(ob);
}
void
fl_set_xyplot_xscale(FL_OBJECT * ob, int major, int minor)
{
Plot_h *p;
if (ob == 0 || ob->objclass != FL_XYPLOT)
return;
p = (Plot_h *) ob->spec;
p->xmajor = major;
p->xminor = minor;
fl_redraw_object(ob);
}
void
fl_set_xyplot_yscale(FL_OBJECT * ob, int major, int minor)
{
Plot_h *p;
if (ob == 0 || ob->objclass != FL_XYPLOT)
return;
p = (Plot_h *) ob->spec;
p->ymajor = major;
p->yminor = minor;
fl_redraw_object(ob);
}
/********************************************************************
* Add arbitary text, but don't draw it (yet)
*******************************************************************/
void
fl_add_xyplot_text(FL_OBJECT * ob, float x, float y, int i,
const char *text, int vert, int col, float size, int style)
{
Plot_h *p;
if (ob == 0 || ob->objclass != FL_XYPLOT || i >= MAXTEXT)
return;
if (!ob->form->doublebuf && ob->form->visible && ob->visible)
draw_xyplot_text(ob, 1);
p = (Plot_h *) ob->spec;
p->tx[i] = x;
p->ty[i] = y;
if (col >= 0)
p->tcol[i] = col;
if (size > 0.0)
p->tsize[i] = size;
p->vert[i] = vert;
p->tstyle[i] = style;
if (!text)
p->text[i][0] = '\0';
else
{
strncpy(p->text[i], text, MAXTEXTL);
p->text[i][MAXTEXTL - 1] = '\0';
}
if (!ob->form->doublebuf && ob->form->visible && ob->visible)
draw_xyplot_text(ob, 0);
else
fl_redraw_object(ob);
}
/*************************************************************
* Add the text and drawit
************************************************************/
void
fl_set_xyplot_text(FL_OBJECT * ob, float x, float y, int i,
const char *text, int vert, int col, float size, int style)
{
if (ob == 0 || ob->objclass != FL_XYPLOT || i >= MAXTEXT)
return;
fl_add_xyplot_text(ob, x, y, i, text, vert, col, size, style);
fl_redraw_object(ob);
}
void
fl_set_xyplot_type(FL_OBJECT * ob, int type)
{
if (ob == 0 || ob->objclass != FL_XYPLOT)
return;
if (type < 0 || type >= FL_XYPLOT_MAXTYPE)
type = 0;
ob->type = type;
fl_redraw_object(ob);
}
#include <math.h>
#define ADVANCE 0.2 /* shoulde not be greater than 0.25 */
#define FACTOR 1.8 /* max major expansion */
static float trunc_f(float, int);
static float
gen_tic(float tmin, float tmax, int major, int minor)
{
float r_range, l_range, n_range;
float tic;
int ipow, digit;
/* handle special case: Min, MAX and one tic */
if (major == 1 && minor == 2)
{
tic = (tmax - tmin) * 0.5 * 0.999;
return tic;
}
r_range = tmax - tmin;
l_range = (float) log10(r_range);
ipow = (int) ((l_range > 0.0) ? (int) l_range : (int) l_range - 1);
/* normalized range is between 0 and 10 */
n_range = (float) pow(10.0, (l_range - ipow));
n_range += ADVANCE;
tic = n_range / major;
digit = (tic < 1.0);
tic = trunc_f(tic, digit);
tic /= (float) minor;
tic = trunc_f(tic, 1);
tic *= pow(10.0, (double) ipow);
/* Final check */
n_range = (r_range / (tic * minor * major));
if (n_range > FACTOR)
{
ipow = (n_range / FACTOR);
if (ipow >= 1)
tic *= 2.0 * ipow;
else
tic *= 2.0 * n_range / FACTOR;
tic = trunc_f(tic, 1);
}
return tic;
}
/*
* truncate a floating point number to requested significant digits
*/
static float
trunc_f(float f, int digit)
{
int ipow, itmp, c;
float expon, tmp;
if (fabs(f) < 1.e-8)
return 0.0;
if (digit < 0)
digit = 1;
if (!digit)
{
if (f > 0.5)
return 1.0;
else if (f < 0.5)
return 0.0;
else
{
itmp = f;
return (float) itmp;
}
}
c = digit - 1;
expon = log10(f);
ipow = (expon > 0.0) ? (int) expon : (int) expon - 1;
tmp = pow(10.0, expon - (double) ipow);
tmp += ADVANCE;
tmp *= pow(10.0, (double) c);
itmp = tmp;
tmp = (float) itmp;
tmp *= pow(10.0, (double) (ipow - c));
return tmp;
}
/***********************************************************
* Forms that show 4 xyplots for histograms
**********************************************************/
static FL_FORM *chart4;
static FL_OBJECT *chartdone, *ch[4], *txt[4];
static void create_form_chart4(void);
static char *ylab[4], *xlab[4], *title[4];
static float ch4ymin[4] =
{
0, 0, 0, 0
};
static float ch4ymax[4] =
{
-1, -1, -1, -1
};
static int lstyle = FL_LINEFILL_XYPLOT;
/*ARGSUSED*/
static void
change_chart4_style(FL_OBJECT * s, long p)
{
int i;
create_form_chart4();
fl_freeze_form(chart4);
lstyle++;
lstyle %= FL_XYPLOT_MAXTYPE;
for (i = 0; i < 4; i++)
fl_set_xyplot_type(ch[i], lstyle);
fl_unfreeze_form(chart4);
}
/* ARGSUSED */
static void
hide_chart4(FL_OBJECT * ob, long q)
{
static long hmenu = -1;
static int xmin = 0, xmax = 255;
static int ymin = 0, ymax = 100;
int i;
if (hmenu < 0)
hmenu = defpup("Histogram%t|XScale|Yscale|Reset|Style|Done %x100");
switch (dopup(hmenu))
{
case 100:
bit_hide_form(chart4);
fl_clear_xyplot(ch[0]);
fl_clear_xyplot(ch[1]);
fl_clear_xyplot(ch[2]);
fl_clear_xyplot(ch[3]);
break;
case 1:
get2int("Min Pixel Value", &xmin, 0, 255,
"Max Pixel Value", &xmax, 0, 255,
0, 0, -1, 0);
fl_freeze_form(chart4);
for (i = 0; i < 4; i++)
fl_set_xyplot_xbounds(ch[i], xmin, xmax);
fl_unfreeze_form(chart4);
break;
case 2:
get2int("Min Percentage", &ymin, 0, 100,
"Max Percentage", &ymax, 0, 100, 0, 0, -1, 0);
fl_freeze_form(chart4);
for (i = 0; i < 4; i++)
fl_set_xyplot_ybounds(ch[i], ymin * 0.01, ymax * 0.01);
fl_unfreeze_form(chart4);
break;
case 3:
/*
* need to force a redraw (via unfreeze) because set_auto does not
* draw the object automatically
*/
fl_freeze_form(chart4);
for (i = 0; i < 4; i++)
fl_set_xyplot_autobounds(ch[i], 1, 1);
fl_unfreeze_form(chart4);
break;
case 4:
change_chart4_style(0, 0);
break;
}
}
void
set_chart4_ybounds(float *ymin, float *ymax)
{
int i;
for (i = 0; i < 4; i++)
{
ch4ymin[i] = ymin[i];
ch4ymax[i] = ymax[i];
}
}
void
set_chart4_text(const char *l1, const char *l2, const char *l3, const char *l4)
{
create_form_chart4();
fl_freeze_form(chart4);
fl_set_object_label(txt[0], l1);
fl_set_object_label(txt[1], l2);
fl_set_object_label(txt[2], l3);
fl_set_object_label(txt[3], l4);
fl_unfreeze_form(chart4);
}
void
set_chart4_style(long p)
{
lstyle = p;
create_form_chart4();
fl_set_xyplot_type(ch[0], p);
fl_set_xyplot_type(ch[1], p);
fl_set_xyplot_type(ch[2], p);
fl_set_xyplot_type(ch[3], p);
}
void
show_chart4(const char *ctitle, float *x, float *y[], int n)
{
int i;
create_form_chart4();
minsize(300, 300);
fl_freeze_form(chart4);
fl_set_object_label(chartdone, ctitle);
for (i = 0; i < 4; i++)
{
fl_set_xyplot(ch[i], x, y[i], n, title[i], xlab[i], ylab[i]);
if (ch4ymin[i] < ch4ymax[i])
fl_set_xyplot_ybounds(ch[i], ch4ymin[i], ch4ymax[i]);
ch4ymin[i] = 0.0;
ch4ymax[i] = -1.0;
}
fl_unfreeze_form(chart4);
bit_show_form(chart4, FL_PLACE_FREE, 1, ctitle);
}
static FL_OBJECT *hhh;
void
set_chart4_help(int h)
{
create_form_chart4();
fl_set_call_back(hhh, help_cb, h);
}
static void
create_form_chart4(void)
{
FL_OBJECT *obj;
if (chart4)
return;
chart4 = fl_bgn_form(FL_NO_BOX, 445.0, 515.0);
obj = fl_add_box(FL_FLAT_BOX, 0.0, 0.0, 445.0, 515.0, "");
hhh = fl_add_button(FL_HB, 0.0, 0.0, 445, 515, "");
ch[0] = fl_add_xyplot(lstyle, 10.0, 10.0, 420.0, 110.0, "");
fl_set_xyplot_colors(ch[0], FL_RED, FL_BLACK);
ch[1] = fl_add_xyplot(lstyle, 10.0, 125.0, 420.0, 110.0, "");
fl_set_xyplot_colors(ch[1], FL_GREEN, FL_BLACK);
ch[2] = fl_add_xyplot(lstyle, 10.0, 240.0, 420.0, 110.0, "");
fl_set_xyplot_colors(ch[2], FL_BLUE, FL_BLACK);
ch[3] = fl_add_xyplot(lstyle, 10.0, 355.0, 420.0, 110.0, "");
fl_set_xyplot_colors(ch[3], FL_WHITE, FL_BLACK);
chartdone = obj = fl_add_button(FL_NB, 120.0, 475.0, 215.0, 31.0, "");
fl_set_object_boxtype(obj, FL_RSHADOW_BOX);
fl_set_object_color(obj, FL_MAGIC1, FL_RED);
fl_set_object_lcol(obj, 4);
fl_set_object_lstyle(obj, FL_ENGRAVED_STYLE);
fl_set_call_back(obj, hide_chart4, 0);
txt[0] = obj = fl_add_text(FL_NT, 240.0, 85.0, 150.0, 20.0, "");
fl_set_object_lsize(txt[0], FL_SMALL_FONT);
txt[1] = obj = fl_add_text(FL_NT, 240.0, 200.0, 150.0, 20.0, "");
fl_set_object_lsize(txt[1], FL_SMALL_FONT);
txt[2] = obj = fl_add_text(FL_NT, 240.0, 315.0, 150.0, 20.0, "");
fl_set_object_lsize(txt[2], FL_SMALL_FONT);
txt[3] = obj = fl_add_text(FL_NT, 240.0, 433.0, 150.0, 20.0, "");
fl_set_object_lsize(txt[3], FL_SMALL_FONT);
fl_end_form();
}
/*******************************************************************
* Get an angle. in tenth of a degree
******************************************************************/
static FL_FORM *dirform;
static FL_OBJECT *cdir, *dircancel, *dirok, *dirtitle;
static void create_form_dir(void);
static float dirval;
/* cancel returns -1, else 0 or positive */
/* also the val should be in tenth of a degree */
int
get_orientation(const char *dirprompt, int *val, int im)
{
int def = *val, done;
short garb;
FL_OBJECT *ret;
create_form_dir();
fl_set_object_label(dirtitle, dirprompt);
fl_set_object_label(cdir, ftoa(def * 0.1, 1));
bit_show_form(dirform, FL_PLACE_MOUSE, 0, dirprompt);
do
{
done = ((ret = fl_do_forms()) == dircancel || ret == dirok);
if (ret == FL_EVENT)
(void) bit_qread(&garb);
}
while (!done && !im);
*val = (((ret != dircancel) ? dirval : def) * 10.0);
if (done)
bit_hide_form(dirform);
return ret == dircancel ? -1 : done;
}
/*************************************************************/
#define MAXSTEP 5.0
#define MINSTEP 0.5
/* ARGSUSED */
static void
dir_shortcuts(FL_OBJECT * ob, long q)
{
static int vals[] =
{
225, -90, -45, 180, 0, 0, 125, 90, 45
};
dirval = vals[q];
fl_set_object_label(cdir, ftoa(dirval, 1));
fl_qenter(SPACEKEY, 0);
}
/* ARGSUSED */
static void
change_it(FL_OBJECT * ob, long q)
{
if (q == 4)
dirval -= MINSTEP;
else if (q == 44)
dirval -= MAXSTEP;
else if (q == 66)
dirval += MAXSTEP;
else if (q == 6)
dirval += MINSTEP;
if (dirval > 360)
dirval -= 360.0;
if (dirval < -360)
dirval += 360.0;
fl_set_object_label(cdir, ftoa(dirval, 1));
fl_qenter(SPACEKEY, 1);
}
static void
create_form_dir(void)
{
FL_OBJECT *obj;
static const char *lab[] =
{
"@1", "@2", "@3", "@4", "@circle", "@6", "@7", "@8", "@9"
};
int i, j, k;
float x, y, dx, dy;
if (dirform)
return;
dirform = fl_bgn_form(FL_NO_BOX, 170.0, 190.0);
obj = fl_add_box(FL_UP_BOX, 0.0, 0.0, 170.0, 190.0, "");
dirtitle = obj = fl_add_text(FL_NO_BOX, 10, 165, 150, 15, "");
fl_set_object_lcol(obj, FL_BLUE);
fl_set_object_align(obj, FL_ALIGN_CENTER);
fl_set_object_lstyle(obj, FL_BOLD_STYLE);
fl_bgn_group();
dx = dy = 30.0;
x = 40;
for (j = 0, k = 0, y = 70.0; j < 3; j++, y += dy, x = 40)
{
for (x = 40, i = 0; i < 3; i++, x += dx, k++)
{
obj = fl_add_button(FL_NB, x, y, dx, dy, lab[k]);
fl_set_object_boxtype(obj, FL_FRAME_BOX);
fl_set_object_color(obj, 47, 4);
fl_set_object_lcol(obj, 1);
fl_set_call_back(obj, dir_shortcuts, k);
}
}
fl_end_group();
obj = fl_add_button(FL_TB, 10.0, 40.0, 25.0, 25.0, "@<<");
fl_set_object_boxtype(obj, FL_FRAME_BOX);
fl_set_object_color(obj, 47, 4);
fl_set_object_lcol(obj, 4);
fl_set_call_back(obj, change_it, 44);
obj = fl_add_button(FL_TB, 35.0, 40.0, 25.0, 25.0, "@<");
fl_set_object_boxtype(obj, FL_FRAME_BOX);
fl_set_object_color(obj, 47, 4);
fl_set_call_back(obj, change_it, 4);
fl_set_object_lcol(obj, 4);
obj = fl_add_button(FL_TB, 135.0, 40.0, 25.0, 25.0, "@>>");
fl_set_object_boxtype(obj, FL_FRAME_BOX);
fl_set_object_color(obj, 47, 4);
fl_set_object_lcol(obj, 4);
fl_set_call_back(obj, change_it, 66);
obj = fl_add_button(FL_TB, 110.0, 40.0, 25.0, 25.0, "@>");
fl_set_object_boxtype(obj, FL_FRAME_BOX);
fl_set_object_color(obj, 47, 4);
fl_set_object_lcol(obj, 4);
fl_set_call_back(obj, change_it, 6);
cdir = obj = fl_add_text(FL_NT, 60.0, 40.0, 50.0, 25.0, "");
fl_set_object_boxtype(obj, FL_FRAME_BOX);
fl_set_object_lcol(obj, 4);
fl_set_object_lsize(obj, 10.0);
fl_set_object_align(obj, FL_ALIGN_CENTER);
dirok = obj = fl_add_button(FL_NB, 100.0, 10.0, 60.0, 25.0, "Done");
fl_set_object_lsize(obj, 10.0);
fl_end_form();
}
/****************************************************************
* FORM class RGB_ICON.
* A hack. Not up to the form standard
***************************************************************{*/
#include "bit.h"
#include "extern.h"
#include "dmalloc.h"
typedef struct
{
int val; /* if pressed */
int dblclk; /* if double clicked */
rgba_t **rgba; /* the raster */
int external; /* if rgba is alloced elsewhere */
int w, h; /* dimension of the icon */
char *filename; /* the filenae for this icon */
char *info; /* other info about this icon */
}
ICON_SPEC;
static void
free_icon_image(ICON_SPEC * sp)
{
if (!sp->external)
free_mat(sp->rgba);
sp->rgba = 0;
sp->external = 0;
}
static void
free_rgb_icon(ICON_SPEC * sp)
{
free_icon_image(sp);
if (sp->filename)
free(sp->filename);
if (sp->info)
free(sp->info);
sp->info = sp->filename = 0;
}
/***********************************************************
* Check if an icon is pushed
***********************************************************/
int
fl_get_icon(FL_OBJECT * ob)
{
return ((ICON_SPEC *) (ob->spec))->val;
}
/************************************************************
* push it from within program
***********************************************************/
void
fl_set_icon(FL_OBJECT * ob, int pushed)
{
((ICON_SPEC *) (ob->spec))->val = pushed;
if (ob->type == FL_RADIO_ICON)
ob->pushed = pushed;
fl_redraw_object(ob);
}
/***********************************************************
* Check if an icon is double clicked on
**********************************************************/
int
fl_get_icon_dblclk(FL_OBJECT * ob)
{
return ((ICON_SPEC *) (ob->spec))->dblclk;
}
#include <math.h>
static void
draw_image(FL_OBJECT * ob, ICON_SPEC * sp, int *x, int *y)
{
int w, h, xx, yy;
unsigned long *ras;
/* if no image, generate a default */
if (!sp->rgba)
{
cpack(0x000000ff);
w = sp->w = ob->w - 10;
h = sp->h = ob->h - 10;
gl_plus(ob->x + ob->w / 2, ob->y + ob->h / 2, w / 2, h / 2, 0, 450);
xx = ob->x + (ob->w - w) / 2;
yy = ob->y + (ob->h - h) / 2;
}
else
{
ras = sp->rgba[0];
w = sp->w;
h = sp->h;
xx = ob->x + (ob->w - w) / 2;
yy = ob->y + (ob->h - h) / 2;
lrectwrite(xx, yy, xx + w - 1, yy + h - 1, ras);
}
*x = xx;
*y = yy;
}
static void
draw_icon(FL_OBJECT * ob)
{
ICON_SPEC *sp = (ICON_SPEC *) ob->spec;
int x, y;
long owin = winget();
set_current_window(ob->form->window);
if (sp->val && ob->boxtype == FL_UP_BOX)
fl_drw_box(FL_DOWN_BOX, ob->x, ob->y, ob->w, ob->h, ob->col1, 2);
else
fl_drw_box(ob->boxtype, ob->x, ob->y, ob->w, ob->h, ob->col1, 2);
draw_image(ob, sp, &x, &y);
fl_drw_text_beside(ob->align, ob->x, ob->y, ob->w, ob->h,
ob->lcol, ob->lsize, ob->lstyle, ob->label);
if (ob->belowmouse || sp->val)
{
cpack(sp->val ? 0x00ffff00 : 0x0000ffff);
recti(x, y, x + sp->w - 1, y + sp->h - 1);
if (sp->val)
fl_drw_text_beside(ob->align, ob->x, ob->y, ob->w, ob->h,
FL_RED, ob->lsize, ob->lstyle, ob->label);
}
set_current_window(owin);
}
/*******************************************************************
* Handle mouse events for icons
*
* Double click is considered true if two clicks are seperated
* by less than DSEP (in milli-seconds)
******************************************************************/
#define DSEP 250
/*ARGSUSED*/
static int
handle_icon(FL_OBJECT * ob, int event, float mx, float my, char k)
{
int ret = 0;
ICON_SPEC *sp = ((ICON_SPEC *) ob->spec);
static int oldval;
int newval;
switch (event)
{
case FL_DRAW:
draw_icon(ob);
return 0;
case FL_ENTER:
case FL_LEAVE:
fl_redraw_object(ob);
return 0;
case FL_PUSH:
oldval = sp->val;
sp->val = !sp->val;
sp->dblclk = 0;
fl_redraw_object(ob);
return (ob->type == FL_TOUCH_ICON);
case FL_RELEASE:
if (ob->type == FL_RADIO_ICON)
return 1;
else if (ob->type == FL_PUSH_ICON)
return (sp->val != oldval);
else if (ob->type == FL_DBL_CLK_ICON)
{
sp->dblclk = (time_passed() < DSEP);
reset_time();
return (sp->dblclk || (sp->val != oldval));
}
else if (sp->val == 0)
return 0;
sp->val = 0;
fl_redraw_object(ob);
return (ob->type != FL_TOUCH_ICON);
case FL_MOUSE:
if (ob->type != FL_RADIO_ICON)
{
if (mx < ob->x || mx > (ob->x + ob->w) ||
my < ob->y || my > (ob->y + ob->h))
{
newval = oldval;
}
else
{
newval = !oldval;
}
if (sp->val != newval)
{
sp->val = newval;
fl_redraw_object(ob);
}
}
return (sp->val && ob->type == FL_TOUCH_ICON);
case FL_FREEMEM:
free_rgb_icon(sp);
break;
}
return ret;
}
static FL_OBJECT *
fl_create_icon(int t, float x, float y, float w, float h,
const char *lab)
{
FL_OBJECT *ob;
ICON_SPEC *sp;
ob = fl_make_object(FL_RGB_ICON, t, x, y, w, h, lab, handle_icon);
ob->boxtype = FL_ICON_BOXTYPE;
ob->col1 = FL_MAGIC1;
ob->col2 = FL_MAGIC2;
ob->spec = calloc(1, sizeof(ICON_SPEC));
ob->radio = (t == FL_RADIO_ICON);
ob->lcol = FL_ICON_LCOL;
ob->align = FL_ICON_ALIGN;
ob->lsize = FL_ICON_LSIZE;
ob->lstyle = FL_ICON_LSTYLE;
/* initialization specific to rgb images */
sp = (ICON_SPEC *) ob->spec;
sp->rgba = 0;
sp->filename = sp->info = 0;
sp->external = 0;
return ob;
}
FL_OBJECT *
fl_add_icon(int type, float x, float y, float w, float h,
const char *lab)
{
FL_OBJECT *ob = fl_create_icon(type, x, y, w, h, lab);
fl_add_object(fl_current_form, ob);
return ob;
}
FL_OBJECT *
fl_set_icon_bitmap(FL_OBJECT * ob, int w, int h, rgba_t **ras, int ext)
{
ICON_SPEC *sp = ((ICON_SPEC *) ob->spec);
free_icon_image(sp);
sp->w = w;
sp->h = h;
sp->external = ext;
sp->rgba = ras;
/* if not external, need to copy it */
if (!ext)
{
sp->rgba = get_mat(h, w, sizeof(long));
if (ras)
memcpy(sp->rgba[0], ras[0], sizeof(unsigned long) * w * h);
}
return ob;
}
static rgba_t **
load_icon(const char *fname, int *w, int *h)
{
IPTR tmp;
int oreport = report_level;
rgba_t **pp = 0;
report_level = -1;
if ((tmp = load_image(fname)))
{
*w = tmp->w;
*h = tmp->h;
pp = tmp->mraster;
tmp->mraster = 0;
}
free_image(tmp);
report_level = oreport;
return pp;
}
FL_OBJECT *
fl_set_icon_file(FL_OBJECT * ob, const char *f)
{
ICON_SPEC *sp = (ICON_SPEC *) ob->spec;
if (f && (!sp->filename || strcmp(f, sp->filename) || !sp->rgba))
{
free_icon_image(sp);
StrReDup(sp->filename, f);
sp->rgba = load_icon(sp->filename, &sp->w, &sp->h);
}
return ob;
}
/******************************************************************
* Change the associated filename only.
******************************************************************/
void
fl_set_icon_info(FL_OBJECT * ob, const char *f)
{
ICON_SPEC *sp = (ICON_SPEC *) ob->spec;
if (f)
StrReDup(sp->info, f);
else
{
if (sp->info)
free(sp->info);
sp->info = 0;
}
}
const char *
fl_get_icon_info(FL_OBJECT * ob)
{
ICON_SPEC *sp = (ICON_SPEC *) ob->spec;
return sp->info;
}
/*******************************************************************
* END OF RGB_ICON CLASS
******************************************************************} */
/******************************************************************
* Active BITMAP class
******************************************************************{*/
typedef struct
{
int val; /* true if pressed */
int col; /* color shown when focused */
int w, h; /* bitmap size */
char *bits; /* the actual bitmap */
}
Abitmap_t;
static void
ab_init(Abitmap_t * ab)
{
ab->val = ab->w = ab->h = 0;
ab->col = FL_BLUE; /* red is default cursor, look bad */
}
static unsigned long thebits[FL_BITMAP_MAXSIZE];
static void
draw_bitmap(FL_OBJECT * ob)
{
Abitmap_t *sp = ((Abitmap_t *) (ob->spec));
int i, j, k = 0, aoffset;
int col;
short rgb[2][3], *cc;
int xx, yy; /* position of bitmap */
col = (sp->val ? sp->col : ob->col1);
if (ob->belowmouse && (col == FL_BLACK || col == FL_INACTIVE))
col = sp->col;
/* Draw the box */
if (ob->boxtype == FL_UP_BOX && sp->val)
fl_drw_box(FL_DOWN_BOX, ob->x, ob->y, ob->w, ob->h, ob->col2,
FL_ACTIVE_BITMAP_BW);
else
fl_drw_box(ob->boxtype, ob->x, ob->y, ob->w, ob->h, ob->col2,
FL_ACTIVE_BITMAP_BW);
fl_drw_text_beside(ob->align, ob->x, ob->y, ob->w, ob->h,
ob->lcol, ob->lsize, ob->lstyle, ob->label);
if (sp->w == 0)
return;
cc = rgb[0];
fl_getmcolor(ob->col2, cc, cc + 1, cc + 2);
cc = rgb[1];
fl_getmcolor(col, cc, cc + 1, cc + 2);
/* Create the bitmap */
for (j = 0; j < sp->h; j++)
{
aoffset = (sp->h - j - 1) * sp->w;
for (i = 0; i < sp->w; i++)
{
cc = rgb[((sp->bits[k + i / 8] & (1 << (i % 8)))) != 0];
thebits[aoffset + i] = 0x10000 * cc[2] + 0x100 * cc[1] + cc[0];
}
k += (sp->w + 7) / 8;
}
/* Calculate position and draw bitmap */
xx = (int) (ob->x + (ob->w - (float) sp->w) / 2.0);
yy = (int) (ob->y + (ob->h - (float) sp->h) / 2.0);
lrectwrite(xx, yy, xx - 1 + sp->w, yy - 1 + sp->h, thebits);
}
/* ARGSUSED */
static int
handle_abitmap(FL_OBJECT * ob, int event,
float mx, float my, char key)
{
int oval = 0, nval;
Abitmap_t *sp = (Abitmap_t *) ob->spec;
switch (event)
{
case FL_DRAW:
draw_bitmap(ob);
break;
case FL_ENTER:
case FL_LEAVE:
fl_redraw_object(ob);
return 0;
case FL_PUSH:
oval = sp->val;
sp->val = !sp->val;
fl_redraw_object(ob);
return 0;
case FL_RELEASE:
if (ob->type == FL_RADIO_BITMAP)
return 1;
else if (ob->type == FL_PUSH_BITMAP)
return (sp->val != oval);
else if (sp->val == 0)
return 0;
sp->val = 0;
fl_redraw_object(ob);
return 1;
case FL_MOUSE:
if (ob->type != FL_RADIO_BITMAP)
{
if (mx < ob->x || mx > (ob->x + ob->w) ||
(my < ob->y || my < (ob->y + ob->h)))
nval = oval;
else
nval = !oval;
if (sp->val != nval)
{
sp->val = nval;
fl_redraw_object(ob);
}
}
return 0;
case FL_FREEMEM:
free(ob->spec);
break;
}
return 0;
}
static FL_OBJECT *
create_ab(int objclass, int type, float x, float y, float w, float h,
const char *label)
{
FL_OBJECT *ob;
ob = fl_make_object(objclass, type, x, y, w, h, label, handle_abitmap);
ob->boxtype = FL_ACTIVE_BITMAP_BOXTYPE;
ob->col1 = FL_BLACK;
ob->col2 = FL_MAGIC1;
ob->lcol = FL_BLACK;
ob->align = FL_ALIGN_CENTER;
ob->active = 1;
ob->radio = type == FL_RADIO_BITMAP;
ob->spec = (int *) fl_malloc(sizeof(Abitmap_t));
/* specific to ab */
ab_init((Abitmap_t *) ob->spec);
return ob;
}
static FL_OBJECT *
fl_create_active_bitmap(int type, float x, float y, float w, float h,
const char *label)
{
return create_ab(FL_ACTIVE_BITMAP, type, x, y, w, h, label);
}
FL_OBJECT *
fl_add_active_bitmap(int type, float x, float y, float w, float h,
const char *label)
{
FL_OBJECT *ob;
ob = fl_create_active_bitmap(type, x, y, w, h, label);
fl_add_object(fl_current_form, ob);
return ob;
}
int
fl_get_active_bitmap(FL_OBJECT * ob)
{
return (ob->objclass != FL_ACTIVE_BITMAP ? 0 :
((Abitmap_t *) (ob->spec))->val);
}
void
fl_set_active_bitmap(FL_OBJECT * ob, int y)
{
if (ob->objclass == FL_ACTIVE_BITMAP)
{
((Abitmap_t *) (ob->spec))->val = y;
if (ob->type == FL_RADIO_BITMAP)
ob->pushed = y;
}
}
FL_OBJECT *
fl_set_bitmap_bitmap(FL_OBJECT * ob, int w, int h, char *b)
{
Abitmap_t *sp;
if (ob && ob->objclass == FL_ACTIVE_BITMAP)
{
sp = (Abitmap_t *) (ob->spec);
sp->w = w;
sp->h = h;
sp->bits = b;
if (w * h > FL_BITMAP_MAXSIZE)
sp->h = FL_BITMAP_MAXSIZE / w;
fl_redraw_object(ob);
}
return ob;
}
void
fl_set_active_bitmap_color(FL_OBJECT * ob, int c)
{
((Abitmap_t *) (ob->spec))->col = c;
}
/***************************************************************
* END of Active Bitmap Class
**************************************************************}*/
/*******************************************************
* Get 2 integers and a flag
*******************************************************/
static void create_form_int2(void);
static FL_OBJECT *ct1, *ct2, *bobj, *hobj;
static FL_FORM *input2;
static FL_OBJECT *int2cancel, *int2ok;
int
get2int(const char *p1, int *v1, int cv1i, int cv1f,
const char *p2, int *v2, int cv2i, int cv2f,
const char *bl1, int *b1, int hindex, int im)
{
int sv1 = *v1, sv2 = *v2, sb1 = b1 ? *b1 : 0;
int v1step1, v1step2;
int v2step1, v2step2;
FL_OBJECT *obj;
short val;
create_form_int2();
((bl1 && *bl1) ? fl_show_object : fl_hide_object) (bobj);
fl_set_button(bobj, *b1);
fl_set_object_label(bobj, bl1);
get_i_step(cv1i, cv1f, &v1step1, &v1step2);
get_i_step(cv2i, cv2f, &v2step1, &v2step2);
fl_set_counter_precision(ct1, 0);
fl_set_counter_precision(ct2, 0);
fl_set_counter_bounds(ct1, cv1i, cv1f);
fl_set_counter_bounds(ct2, cv2i, cv2f);
fl_set_counter_step(ct1, v1step1, v1step2);
fl_set_counter_step(ct2, v2step1, v2step2);
fl_set_counter_return(ct1, im);
fl_set_counter_return(ct2, im);
fl_set_counter_value(ct1, sv1);
fl_set_counter_value(ct2, sv2);
fl_set_object_label(ct1, p1 ? p1 : "Integer");
fl_set_object_label(ct2, p2 ? p2 : "Integer");
deactivate_all_forms();
set_cursor(bit_show_form(input2, FL_PLACE_MOUSE, 0, "Input2"), CUR_HAND);
do
{
obj = fl_do_forms();
if (obj == FL_EVENT)
bit_qread(&val);
else if (obj == bobj)
*b1 = fl_get_button(bobj);
else if (obj == hobj)
help_cb(0, hindex);
}
while (obj != int2cancel && obj != int2ok && !im);
*v1 = (obj == int2cancel) ? sv1 : fl_get_counter_value(ct1);
*v2 = (obj == int2cancel) ? sv2 : fl_get_counter_value(ct2);
if (b1)
{
*b1 = (obj == int2cancel) ? sb1 : fl_get_button(bobj);
}
fl_activate_all_forms();
if (obj == int2cancel || obj == int2ok)
bit_hide_form(input2);
return obj == int2cancel ? -1 : (obj == int2ok);
}
static void
create_form_int2(void)
{
FL_OBJECT *obj;
if (input2)
return;
input2 = fl_bgn_form(FL_NO_BOX, 330.0, 150.0);
obj = fl_add_box(FL_UP_BOX, 0.0, 0.0, 330.0, 150.0, "");
hobj = fl_add_button(FL_HB, 0.0, 0.0, 330.0, 150.0, "");
ct1 = obj = fl_add_counter(FL_NC, 20.0, 90.0, 180.0, 30.0, "");
fl_set_object_lsize(obj, 10.0);
fl_set_object_align(obj, FL_ALIGN_TOP);
ct2 = obj = fl_add_counter(FL_NC, 20.0, 20.0, 180.0, 30.0, "");
fl_set_object_lsize(obj, 10.0);
fl_set_object_align(obj, FL_ALIGN_TOP);
int2cancel = obj = fl_add_button(FL_NB, 230.0, 35.0, 80.0, 25.0, "Cancel");
fl_set_object_lsize(obj, 10.0);
fl_set_object_color(obj, FL_MAGIC1, FL_YELLOW);
int2ok = obj = fl_add_button(FL_NB, 230.0, 10.0, 80.0, 25.0, "OK");
fl_set_object_lsize(obj, 10.0);
fl_set_object_color(obj, FL_MAGIC1, FL_GREEN);
bobj = obj = fl_add_roundbutton(FL_PB, 230.0, 110.0, 30.0, 30.0, "");
fl_set_object_lsize(obj, 10.0);
fl_end_form();
}